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 { .icon-menu .option {
display: block; display: block;
margin: 0px 0 20px 0; margin: 0 0 20px 0;
background: var(--color-bg-box); background: var(--color-bg-box);
box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.1); box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.1);
color: inherit; color: inherit;
@ -457,6 +457,10 @@ p.authorization-code {
color: var(--color-text-dull); color: var(--color-text-dull);
} }
.icon-menu .option-actions {
text-align: right;
}
.icon-menu .option.empty:hover, .icon-menu .option.empty:hover,
.icon-menu .option.static:hover { .icon-menu .option.static:hover {
border: 2px solid rgba(255, 255, 255, 0); border: 2px solid rgba(255, 255, 255, 0);
@ -482,8 +486,20 @@ p.authorization-code {
font-size: 200%; font-size: 200%;
} }
.icon-menu .option .handle { .icon-menu .option.hashtags {
margin-right: 20px; 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 { .icon-menu .option .pill {
@ -500,16 +516,10 @@ p.authorization-code {
} }
.icon-menu .option time { .icon-menu .option time {
float: right;
color: var(--color-text-duller); color: var(--color-text-duller);
margin: 14px 0 0 0; margin: 14px 0 0 0;
} }
.icon-menu .option .right {
display: inline-block;
float: right;
}
.icon-menu .option button { .icon-menu .option button {
margin-top: 8px; margin-top: 8px;
margin-right: 20px; margin-right: 20px;
@ -1015,6 +1025,34 @@ table.metadata td .emoji {
min-width: 16px; 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 */ /* Posts */
.post { .post {
@ -1043,31 +1081,24 @@ form .post {
.post .icon { .post .icon {
height: 48px; height: 48px;
width: auto; width: auto;
float: left;
} }
.post.mini .icon { .post.mini .icon {
height: 28px; height: 28px;
width: auto; width: auto;
float: left;
} }
.post .emoji { .post .emoji {
height: 18px; height: 18px;
} }
.post .handle { .post .post-banner {
display: block; display: flex;
padding: 7px 0 0 64px; align-items: center;
}
.post.mini .handle {
padding: 7px 0 0 36px;
} }
.post time { .post time {
display: block; display: block;
float: right;
color: var(--color-text-duller); color: var(--color-text-duller);
width: 65px; width: 65px;
text-align: center; 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 %} {% load activity_tags %}
<div class="post user" data-takahe-id="{{ identity.id }}"> <div class="post user" data-takahe-id="{{ identity.id }}">
<a href="{{ identity.urls.view }}"> {% include "identity/_identity_banner.html" with identity=identity %}
<img src="{{ identity.local_icon_url.relative }}" class="icon" alt="Avatar for {{ identity.name_or_handle }}" loading="lazy">
</a>
{% if created %} {% if created %}
<time> <time>

View file

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

View file

@ -16,36 +16,32 @@
<section class="icon-menu"> <section class="icon-menu">
{% for identity in page_obj %} {% for identity in page_obj %}
<a class="option" href="{{ identity.urls.view }}"> <a class="option " href="{{ identity.urls.view }}">
<img src="{{ identity.local_icon_url.relative }}" loading="lazy"> <div class="option-content">
<span class="handle"> {% include "identity/_identity_banner.html" with identity=identity link_avatar=False link_handle=False %}
{{ identity.html_name_or_handle }} </div>
<small>@{{ identity.handle }}</small> <div class="option-actions">
</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 %}
<div class="right"> {% if inbound %}
{% if inbound %} <form action="{{ identity.urls.action }}" method="POST" class="follow">
<form action="{{ identity.urls.action }}" method="POST" class="follow"> {% csrf_token %}
{% csrf_token %} {% if identity.id in outbound_ids %}
{% if identity.id in outbound_ids %} <input type="hidden" name="action" value="unfollow">
<input type="hidden" name="action" value="unfollow"> <button class="destructive">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> {% endif %}
{% endif %} </form>
</form> {% endif %}
{% endif %} <time>{{ identity.follow_date | timedeltashort }} ago</time>
</div>
<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

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

View file

@ -20,16 +20,14 @@
<section class="icon-menu"> <section class="icon-menu">
{% for identity in page_obj %} {% for identity in page_obj %}
<a class="option" href="{{ identity.urls.admin_edit }}"> <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"> <div class="option-content">
<span class="handle"> {% include "identity/_identity_banner.html" with identity=identity link_avatar=False link_handle=False %}
{{ identity.html_name_or_handle }} </div>
<small> <div class="option-actions">
{{ identity.handle }}
</small>
</span>
{% if identity.banned %} {% if identity.banned %}
<span class="pill bad">Banned</span> <span class="pill bad">Banned</span>
{% endif %} {% endif %}
</div>
</a> </a>
{% empty %} {% empty %}
<p class="option empty"> <p class="option empty">

View file

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