feat(frontend): replace placeholder avatar with identicons
i don't actually know what the license on the kitten image is, and while it's very unlikely, i don't want to get into legal trouble. it was only ever supposed to be a temporary image, too. identicons aren't the prettiest but at least they have a clear license :3
This commit is contained in:
parent
71d3b42330
commit
74222ead45
10 changed files with 37 additions and 6 deletions
|
@ -42,6 +42,7 @@
|
||||||
"bootstrap-icons": "^1.11.3",
|
"bootstrap-icons": "^1.11.3",
|
||||||
"luxon": "^3.5.0",
|
"luxon": "^3.5.0",
|
||||||
"markdown-it": "^14.1.0",
|
"markdown-it": "^14.1.0",
|
||||||
|
"minidenticons": "^4.2.1",
|
||||||
"pretty-bytes": "^6.1.1",
|
"pretty-bytes": "^6.1.1",
|
||||||
"sanitize-html": "^2.13.1",
|
"sanitize-html": "^2.13.1",
|
||||||
"svelte-tippy": "^1.3.2",
|
"svelte-tippy": "^1.3.2",
|
||||||
|
|
|
@ -23,6 +23,9 @@ importers:
|
||||||
markdown-it:
|
markdown-it:
|
||||||
specifier: ^14.1.0
|
specifier: ^14.1.0
|
||||||
version: 14.1.0
|
version: 14.1.0
|
||||||
|
minidenticons:
|
||||||
|
specifier: ^4.2.1
|
||||||
|
version: 4.2.1
|
||||||
pretty-bytes:
|
pretty-bytes:
|
||||||
specifier: ^6.1.1
|
specifier: ^6.1.1
|
||||||
version: 6.1.1
|
version: 6.1.1
|
||||||
|
@ -1110,6 +1113,10 @@ packages:
|
||||||
resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
|
resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
|
||||||
engines: {node: '>=8.6'}
|
engines: {node: '>=8.6'}
|
||||||
|
|
||||||
|
minidenticons@4.2.1:
|
||||||
|
resolution: {integrity: sha512-oWfFivA0lOx/V/bO/YIJbthB26lV8JXYvhnv9zM2hNd3fzsHTXQ6c6bWZPcvhD3nnOB+lQk/D9lF43BXixrN8g==}
|
||||||
|
engines: {node: '>=15.14.0'}
|
||||||
|
|
||||||
minimatch@3.1.2:
|
minimatch@3.1.2:
|
||||||
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
|
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
|
||||||
|
|
||||||
|
@ -2369,6 +2376,8 @@ snapshots:
|
||||||
braces: 3.0.3
|
braces: 3.0.3
|
||||||
picomatch: 2.3.1
|
picomatch: 2.3.1
|
||||||
|
|
||||||
|
minidenticons@4.2.1: {}
|
||||||
|
|
||||||
minimatch@3.1.2:
|
minimatch@3.1.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
brace-expansion: 1.1.11
|
brace-expansion: 1.1.11
|
||||||
|
|
|
@ -1,16 +1,22 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { DEFAULT_AVATAR } from "$lib";
|
import { minidenticon } from "minidenticons";
|
||||||
|
|
||||||
type Props = { url: string | null; alt: string; lazyLoad?: boolean; size?: number };
|
type Props = { url: string | null; alt: string; lazyLoad?: boolean; size?: number; name: string };
|
||||||
let { url, alt, lazyLoad, size }: Props = $props();
|
let { url, alt, lazyLoad, size, name }: Props = $props();
|
||||||
|
|
||||||
let width = $derived(size || 200);
|
let width = $derived(size || 200);
|
||||||
|
|
||||||
|
let identicon: string | null = $derived.by(() => {
|
||||||
|
if (url) return null;
|
||||||
|
return "data:image/svg+xml;utf8," + encodeURIComponent(minidenticon(name, 50, 80));
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<img
|
<img
|
||||||
class="rounded-circle img-fluid"
|
class="rounded-circle img-fluid"
|
||||||
style="height: {width}px; width: {width}px"
|
style="height: {width}px; width: {width}px"
|
||||||
src={url || DEFAULT_AVATAR}
|
class:identicon={!url}
|
||||||
|
src={url || identicon}
|
||||||
{alt}
|
{alt}
|
||||||
{width}
|
{width}
|
||||||
loading={lazyLoad ? "lazy" : "eager"}
|
loading={lazyLoad ? "lazy" : "eager"}
|
||||||
|
@ -20,4 +26,12 @@
|
||||||
img {
|
img {
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.identicon {
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
background-color: var(--bs-secondary-border-subtle);
|
||||||
|
}
|
||||||
|
|
||||||
|
background-color: var(--bs-light-border-subtle);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -7,12 +7,13 @@
|
||||||
import ShortNoscriptWarning from "./ShortNoscriptWarning.svelte";
|
import ShortNoscriptWarning from "./ShortNoscriptWarning.svelte";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
name: string;
|
||||||
current: string | null;
|
current: string | null;
|
||||||
alt: string;
|
alt: string;
|
||||||
update: (avatar: string) => Promise<void>;
|
update: (avatar: string) => Promise<void>;
|
||||||
updated: boolean;
|
updated: boolean;
|
||||||
};
|
};
|
||||||
let { current, alt, update: onclick, updated }: Props = $props();
|
let { name, current, alt, update: onclick, updated }: Props = $props();
|
||||||
|
|
||||||
const MAX_AVATAR_BYTES = 1_000_000;
|
const MAX_AVATAR_BYTES = 1_000_000;
|
||||||
|
|
||||||
|
@ -40,7 +41,7 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<p class="text-center">
|
<p class="text-center">
|
||||||
<Avatar url={avatarExists ? avatar : current} {alt} />
|
<Avatar {name} url={avatarExists ? avatar : current} {alt} />
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<InputGroup class="mb-2">
|
<InputGroup class="mb-2">
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-4 text-center">
|
<div class="col-md-4 text-center">
|
||||||
<Avatar
|
<Avatar
|
||||||
|
name={"name" in profile ? profile.name : profile.username}
|
||||||
url={profile.avatar_url}
|
url={profile.avatar_url}
|
||||||
alt={$t("avatar-tooltip", { name })}
|
alt={$t("avatar-tooltip", { name })}
|
||||||
lazyLoad={lazyLoadAvatar}
|
lazyLoad={lazyLoadAvatar}
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
<div>
|
<div>
|
||||||
<a href="/@{username}/{member.name}">
|
<a href="/@{username}/{member.name}">
|
||||||
<Avatar
|
<Avatar
|
||||||
|
name={member.name}
|
||||||
url={member.avatar_url}
|
url={member.avatar_url}
|
||||||
lazyLoad
|
lazyLoad
|
||||||
alt={$t("avatar-tooltip", { name: member.display_name })}
|
alt={$t("avatar-tooltip", { name: member.display_name })}
|
||||||
|
|
|
@ -55,6 +55,7 @@
|
||||||
<div class="col-md-3 text-center">
|
<div class="col-md-3 text-center">
|
||||||
<h5>{$t("settings.avatar")}</h5>
|
<h5>{$t("settings.avatar")}</h5>
|
||||||
<Avatar
|
<Avatar
|
||||||
|
name={data.user.username}
|
||||||
url={data.user.avatar_url}
|
url={data.user.avatar_url}
|
||||||
alt={$t("avatar-tooltip", { name: "@" + data.user.username })}
|
alt={$t("avatar-tooltip", { name: "@" + data.user.username })}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
{#each data.members as member (member.id)}
|
{#each data.members as member (member.id)}
|
||||||
<ListGroupItem tag="a" href="/settings/members/{member.id}" data-sveltekit-preload-data="tap">
|
<ListGroupItem tag="a" href="/settings/members/{member.id}" data-sveltekit-preload-data="tap">
|
||||||
<Avatar
|
<Avatar
|
||||||
|
name={member.name}
|
||||||
url={member.avatar_url}
|
url={member.avatar_url}
|
||||||
alt={$t("avatar-tooltip", { name: member.display_name })}
|
alt={$t("avatar-tooltip", { name: member.display_name })}
|
||||||
size={20}
|
size={20}
|
||||||
|
|
|
@ -74,6 +74,7 @@
|
||||||
<div class="col-md">
|
<div class="col-md">
|
||||||
<h4>{$t("settings.avatar")}</h4>
|
<h4>{$t("settings.avatar")}</h4>
|
||||||
<AvatarEditor
|
<AvatarEditor
|
||||||
|
name={data.member.name}
|
||||||
current={data.member.avatar_url}
|
current={data.member.avatar_url}
|
||||||
alt={$t("avatar-tooltip", { name: data.member.name })}
|
alt={$t("avatar-tooltip", { name: data.member.name })}
|
||||||
update={updateAvatar}
|
update={updateAvatar}
|
||||||
|
|
|
@ -91,6 +91,7 @@
|
||||||
<div class="col-md">
|
<div class="col-md">
|
||||||
<h4>{$t("settings.avatar")}</h4>
|
<h4>{$t("settings.avatar")}</h4>
|
||||||
<AvatarEditor
|
<AvatarEditor
|
||||||
|
name={data.user.username}
|
||||||
current={data.user.avatar_url}
|
current={data.user.avatar_url}
|
||||||
alt={$t("avatar-tooltip", { name: "@" + data.user.username })}
|
alt={$t("avatar-tooltip", { name: "@" + data.user.username })}
|
||||||
update={updateAvatar}
|
update={updateAvatar}
|
||||||
|
|
Loading…
Reference in a new issue