Fallback avatars in about 500 bytes. (#269)

Also create a new re-usable identity banner template. Fix super long handles (closes #270)
This commit is contained in:
Tyler Kennedy 2022-12-26 12:14:23 -05:00 committed by GitHub
parent d32a686eb1
commit dab8dd59a7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 159 additions and 93 deletions

View File

@ -438,7 +438,7 @@ p.authorization-code {
.icon-menu .option {
display: block;
margin: 0px 0 20px 0;
margin: 0 0 20px 0;
background: var(--color-bg-box);
box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.1);
color: inherit;
@ -457,6 +457,10 @@ p.authorization-code {
color: var(--color-text-dull);
}
.icon-menu .option-actions {
text-align: right;
}
.icon-menu .option.empty:hover,
.icon-menu .option.static:hover {
border: 2px solid rgba(255, 255, 255, 0);
@ -482,8 +486,20 @@ p.authorization-code {
font-size: 200%;
}
.icon-menu .option .handle {
margin-right: 20px;
.icon-menu .option.hashtags {
display: flex;
align-items: center;
}
.icon-menu .option.hashtags .tag {
min-width: 0;
text-overflow: ellipsis;
overflow: hidden;
flex-grow: 1;
}
.icon-menu .option.hashtags .count {
text-align: right;
}
.icon-menu .option .pill {
@ -500,16 +516,10 @@ p.authorization-code {
}
.icon-menu .option time {
float: right;
color: var(--color-text-duller);
margin: 14px 0 0 0;
}
.icon-menu .option .right {
display: inline-block;
float: right;
}
.icon-menu .option button {
margin-top: 8px;
margin-right: 20px;
@ -1015,6 +1025,34 @@ table.metadata td .emoji {
min-width: 16px;
}
/* Identity banner */
.identity-banner {
display: flex;
align-items: center;
flex-grow: 1;
min-width: 0;
}
.identity-banner .handle {
display: block;
padding: 0 10px;
vertical-align: middle;
min-width: 0;
}
.identity-banner .handle .link,
.identity-banner .handle .small {
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
display: block;
}
.identity-banner .avatar-link {
line-height: 0; /* Fixes a bit of extra padding on the bottom of the link. */
}
/* Posts */
.post {
@ -1043,31 +1081,24 @@ form .post {
.post .icon {
height: 48px;
width: auto;
float: left;
}
.post.mini .icon {
height: 28px;
width: auto;
float: left;
}
.post .emoji {
height: 18px;
}
.post .handle {
display: block;
padding: 7px 0 0 64px;
}
.post.mini .handle {
padding: 7px 0 0 36px;
.post .post-banner {
display: flex;
align-items: center;
}
.post time {
display: block;
float: right;
color: var(--color-text-duller);
width: 65px;
text-align: center;

8
static/js/minidenticons.min.js vendored Normal file
View File

@ -0,0 +1,8 @@
function identicon(t,e=50,i=50){const n=t.split("").reduce(((t,e)=>16777619*((t^e.charCodeAt(0))>>>0)),2166136261);const s=n/16777619%18*20;return[...Array(t?25:0)].reduce(((t,e,i)=>n%(16-i%15)<4?t+`<rect x="${i>14?7-~~(i/5):~~(i/5)}" y="${i%5}" width="1" height="1"/>`:t),`<svg viewBox="-1.5 -1.5 8 8" xmlns="http://www.w3.org/2000/svg" fill="hsl(${s} ${e}% ${i}%)">`)+"</svg>"}
function generate_avatar(handle) {
element.src = URL.createObjectURL(
new Blob([identicon(handle)], {
type: 'image/svg+xml;charset=utf8'
}
));
}

View File

@ -1,9 +1,7 @@
{% load activity_tags %}
<div class="post user" data-takahe-id="{{ identity.id }}">
<a href="{{ identity.urls.view }}">
<img src="{{ identity.local_icon_url.relative }}" class="icon" alt="Avatar for {{ identity.name_or_handle }}" loading="lazy">
</a>
{% include "identity/_identity_banner.html" with identity=identity %}
{% if created %}
<time>

View File

@ -2,32 +2,29 @@
{% load activity_tags %}
<div class="post {% if reply %}reply{% endif %} {{ post.summary_class }}" data-takahe-id="{{ post.id }}" role="article" tabindex="0">
<a href="{{ post.author.urls.view }}" tabindex="-1">
<img src="{{ post.author.local_icon_url.relative }}" class="icon" loading="lazy">
</a>
<time _="on click go url {% if link_original %}{{ post.url }}{% else %}{{ post.urls.view }}{% endif %} then halt">
{% if post.visibility == 0 %}
<i class="visibility fa-solid fa-earth-oceania" title="Public" aria-label="public"></i>
{% elif post.visibility == 1 %}
<i class="visibility fa-solid fa-lock-open" title="Unlisted" aria-label="unlisted"></i>
{% elif post.visibility == 2 %}
<i class="visibility fa-solid fa-lock" title="Followers Only" aria-label="followers only"></i>
{% elif post.visibility == 3 %}
<i class="visibility fa-solid fa-at" title="Mentioned Only" aria-label="mentioned only"></i>
{% elif post.visibility == 4 %}
<i class="visibility fa-solid fa-link-slash" title="Local Only" aria-label="local only"></i>
{% endif %}
{% if post.published %}
<a href="{% if link_original %}{{ post.url }}{% else %}{{ post.urls.view }}{% endif %}" title="{{ post.published }}">{{ post.published | timedeltashort }}</a>
{% else %}
<a href="{% if link_original %}{{ post.url }}{% else %}{{ post.urls.view }}{% endif %}" title="{{ post.created }}">{{ post.created | timedeltashort }}</a>
{% endif %}
</time>
<a href="{{ post.author.urls.view }}" class="handle">
<span class="link">{{ post.author.html_name_or_handle }}</span> <small>@{{ post.author.handle }}</small>
</a>
<div class="post-banner">
{% include "identity/_identity_banner.html" with identity=post.author %}
<div>
<time _="on click go url {% if link_original %}{{ post.url }}{% else %}{{ post.urls.view }}{% endif %} then halt">
{% if post.visibility == 0 %}
<i class="visibility fa-solid fa-earth-oceania" title="Public" aria-label="public"></i>
{% elif post.visibility == 1 %}
<i class="visibility fa-solid fa-lock-open" title="Unlisted" aria-label="unlisted"></i>
{% elif post.visibility == 2 %}
<i class="visibility fa-solid fa-lock" title="Followers Only" aria-label="followers only"></i>
{% elif post.visibility == 3 %}
<i class="visibility fa-solid fa-at" title="Mentioned Only" aria-label="mentioned only"></i>
{% elif post.visibility == 4 %}
<i class="visibility fa-solid fa-link-slash" title="Local Only" aria-label="local only"></i>
{% endif %}
{% if post.published %}
<a href="{% if link_original %}{{ post.url }}{% else %}{{ post.urls.view }}{% endif %}" title="{{ post.published }}">{{ post.published | timedeltashort }}</a>
{% else %}
<a href="{% if link_original %}{{ post.url }}{% else %}{{ post.urls.view }}{% endif %}" title="{{ post.created }}">{{ post.created | timedeltashort }}</a>
{% endif %}
</time>
</div>
</div>
{% if post.summary %}
{% if config_identity.expand_linked_cws %}

View File

@ -16,36 +16,32 @@
<section class="icon-menu">
{% for identity in page_obj %}
<a class="option" href="{{ identity.urls.view }}">
<img src="{{ identity.local_icon_url.relative }}" loading="lazy">
<span class="handle">
{{ identity.html_name_or_handle }}
<small>@{{ identity.handle }}</small>
</span>
<a class="option " href="{{ identity.urls.view }}">
<div class="option-content">
{% include "identity/_identity_banner.html" with identity=identity link_avatar=False link_handle=False %}
</div>
<div class="option-actions">
{% if identity.id in outbound_ids %}
<span class="pill">Following</span>
<span class="pill">Following</span>
{% endif %}
{% if identity.id in inbound_ids %}
<span class="pill">Follows You</span>
{% endif %}
<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>
{% 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>
{% empty %}
<p class="option empty">You have no follows.</p>

View File

@ -5,7 +5,8 @@
{% block content %}
<section class="icon-menu">
{% for hashtag in page_obj %}
<a class="option" href="{{ hashtag.urls.admin_edit }}">
<a class="option hashtags" href="{{ hashtag.urls.admin_edit }}">
<div class="tag">
<i class="fa-solid fa-hashtag"></i>
<span class="handle">
{{ hashtag.display_name }}
@ -13,22 +14,25 @@
{% if hashtag.public %}Public{% elif hashtag.public is None %}Unreviewed{% else %}Private{% endif %}
</small>
</span>
{% if hashtag.stats %}
<span class="handle">
<small>Total:</small>
{{ hashtag.stats.total }}
</span>
{% endif %}
{% if hashtag.aliases %}
<span class="handle">
<small>Aliases:</small>
</div>
{% if hashtag.stats %}
<div class="count">
<span class="handle">
{{ hashtag.stats.total }}
<small>Total</small>
</span>
</div>
{% endif %}
{% if hashtag.aliases %}
<div class="count">
<span class="handle">
{% for alias in hashtag.aliases %}
{{ alias }}{% if not forloop.last %}, {% endif %}
{% endfor %}
</span>
{% endif %}
<small>Aliases</small>
</span>
</div>
{% endif %}
</a>
{% empty %}
<p class="option empty">There are no hashtags yet.</p>

View File

@ -20,16 +20,14 @@
<section class="icon-menu">
{% for identity in page_obj %}
<a class="option" href="{{ identity.urls.admin_edit }}">
<img src="{{ identity.local_icon_url.relative }}" class="icon" alt="Avatar for {{ identity.name_or_handle }}" loading="lazy">
<span class="handle">
{{ identity.html_name_or_handle }}
<small>
{{ identity.handle }}
</small>
</span>
<div class="option-content">
{% include "identity/_identity_banner.html" with identity=identity link_avatar=False link_handle=False %}
</div>
<div class="option-actions">
{% if identity.banned %}
<span class="pill bad">Banned</span>
{% endif %}
</div>
</a>
{% empty %}
<p class="option empty">

View File

@ -12,6 +12,7 @@
<link rel="shortcut icon" href="{{ config.site_icon }}">
<script src="{% static "js/hyperscript.min.js" %}"></script>
<script src="{% static "js/htmx.min.js" %}"></script>
<script src="{% static "js/minidenticons.min.js" %}"></script>
<style>
body {
--color-highlight: {{ config.highlight_color }};

View File

@ -0,0 +1,33 @@
<div class="identity-banner">
{% if link_avatar is False %}
<div class="avatar-link">
{% else %}
<a href="{{ identity.urls.view }}" tabindex="-1" class="avatar-link">
{% endif %}
<img
src="{{ identity.local_icon_url.relative }}"
class="icon"
alt="Avatar for {{ identity.name_or_handle }}"
loading="lazy"
data-handle="{{ identity.name_or_handle }}"
_="on error set my.src to generate_avatar(@data-handle)"
>
{% if link_avatar is False%}
</div>
{% else %}
</a>
{% endif %}
{% if link_handle is False%}
<div class="handle">
{% else %}
<a href="{{ identity.urls.view }}" class="handle">
{% endif %}
<div class="link">{{ identity.html_name_or_handle }}</div>
<small>@{{ identity.handle }}</small>
{% if link_handle is False %}
</div>
{% else %}
</a>
{% endif %}
</div>