Merge pull request #12 from m1k1o/avatars

Custom avatars
This commit is contained in:
Miroslav Šedivý 2020-10-18 15:14:18 +02:00 committed by GitHub
commit 299b1d7bdb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 69 additions and 11 deletions

View File

@ -0,0 +1,52 @@
<template>
<!--
<img :src="`https://ui-avatars.com/api/?name=${seed}&size=${size}`" />
-->
<div class="avatar" :style="{
width: size + 'px',
height: size + 'px',
lineHeight: size + 'px',
fontSize: (size/2) + 'px',
backgroundColor: Background(),
}">
{{ seed.substring(0, 2).toUpperCase() }}
</div>
</template>
<style lang="scss" scoped>
.avatar {
user-select: none;
text-align: center;
background: white;
color: black;
display: inline-block;
overflow: hidden;
border-radius: 50%;
}
</style>
<script lang="ts">
import { Vue, Component, Prop } from 'vue-property-decorator'
@Component({
name: 'neko-avatar',
})
export default class extends Vue {
@Prop(String) readonly seed: string | undefined;
@Prop(Number) readonly size: number | undefined;
Background() {
let a = 0, b = 0, c = 0;
for(let i = 0; i < this.seed.length; i++) {
a += this.seed.charCodeAt(i) * 3;
b += this.seed.charCodeAt(i) * 5;
c += this.seed.charCodeAt(i) * 7;
}
let x = Math.floor(128 + (a % 128));
let y = Math.floor(128 + (b % 128));
let z = Math.floor(128 + (c % 128));
return "rgb(" + x + "," + y + "," + z + ")";
}
}
</script>

View File

@ -4,7 +4,7 @@
<template v-for="(message, index) in history"> <template v-for="(message, index) in history">
<li :key="index" class="message" v-if="message.type === 'text'"> <li :key="index" class="message" v-if="message.type === 'text'">
<div class="author" @contextmenu.stop.prevent="onContext($event, { member: member(message.id) })"> <div class="author" @contextmenu.stop.prevent="onContext($event, { member: member(message.id) })">
<img :src="`https://api.adorable.io/avatars/40/${member(message.id).displayname}.png`" /> <neko-avatar class="avatar" :seed="member(message.id).displayname" :size="40" />
</div> </div>
<div class="content"> <div class="content">
<div class="content-head"> <div class="content-head">
@ -106,7 +106,7 @@
background: $style-primary; background: $style-primary;
margin: 0px 10px 10px 0px; margin: 0px 10px 10px 0px;
img { .avatar {
width: 100%; width: 100%;
} }
} }
@ -329,6 +329,7 @@
import Markdown from './markdown' import Markdown from './markdown'
import Content from './context.vue' import Content from './context.vue'
import Emoji from './emoji.vue' import Emoji from './emoji.vue'
import Avatar from './avatar.vue'
const length = 512 // max length of message const length = 512 // max length of message
@ -338,6 +339,7 @@
'neko-markdown': Markdown, 'neko-markdown': Markdown,
'neko-context': Content, 'neko-context': Content,
'neko-emoji': Emoji, 'neko-emoji': Emoji,
'neko-avatar': Avatar,
}, },
}) })
export default class extends Vue { export default class extends Vue {

View File

@ -3,7 +3,7 @@
<template slot-scope="child" v-if="child.data"> <template slot-scope="child" v-if="child.data">
<li class="header"> <li class="header">
<div class="user"> <div class="user">
<img :src="`https://api.adorable.io/avatars/25/${child.data.member.displayname}.png`" /> <neko-avatar class="avatar" :seed="child.data.member.displayname" :size="25" />
<strong>{{ child.data.member.displayname }}</strong> <strong>{{ child.data.member.displayname }}</strong>
</div> </div>
</li> </li>
@ -80,7 +80,7 @@
align-content: center; align-content: center;
padding: 5px 0; padding: 5px 0;
img { .avatar {
width: 25px; width: 25px;
height: 25px; height: 25px;
border-radius: 50%; border-radius: 50%;
@ -137,11 +137,13 @@
// @ts-ignore // @ts-ignore
import { VueContext } from 'vue-context' import { VueContext } from 'vue-context'
import Avatar from './avatar.vue'
@Component({ @Component({
name: 'neko-context', name: 'neko-context',
components: { components: {
'vue-context': VueContext, 'vue-context': VueContext,
'neko-avatar': Avatar,
}, },
}) })
export default class extends Vue { export default class extends Vue {

View File

@ -4,7 +4,7 @@
<ul class="members-list"> <ul class="members-list">
<li v-if="member"> <li v-if="member">
<div :class="[{ host: member.id === host }, 'self', 'member']"> <div :class="[{ host: member.id === host }, 'self', 'member']">
<img :src="`https://api.adorable.io/avatars/50/${member.displayname}.png`" /> <neko-avatar class="avatar" :seed="member.displayname" :size="50" />
</div> </div>
</li> </li>
<template v-for="(member, index) in members"> <template v-for="(member, index) in members">
@ -13,11 +13,11 @@
:key="index" :key="index"
v-tooltip="{ content: member.displayname, placement: 'bottom', offset: -15, boundariesElement: 'body' }" v-tooltip="{ content: member.displayname, placement: 'bottom', offset: -15, boundariesElement: 'body' }"
> >
<div :class="[{ host: member.id === host, admin: member.admin }, 'member']"> <div
<img :class="[{ host: member.id === host, admin: member.admin }, 'member']"
:src="`https://api.adorable.io/avatars/50/${member.displayname}.png`"
@contextmenu.stop.prevent="onContext($event, { member })" @contextmenu.stop.prevent="onContext($event, { member })"
/> >
<neko-avatar class="avatar" :seed="member.displayname" :size="50" />
</div> </div>
</li> </li>
</template> </template>
@ -130,7 +130,7 @@
border-radius: 50%; border-radius: 50%;
} }
img { .avatar {
border-radius: 50%; border-radius: 50%;
overflow: hidden; overflow: hidden;
width: 100%; width: 100%;
@ -161,11 +161,13 @@
import { Member } from '~/neko/types' import { Member } from '~/neko/types'
import Content from './context.vue' import Content from './context.vue'
import Avatar from './avatar.vue'
@Component({ @Component({
name: 'neko-members', name: 'neko-members',
components: { components: {
'neko-context': Content, 'neko-context': Content,
'neko-avatar': Avatar,
}, },
}) })
export default class extends Vue { export default class extends Vue {