Skip to content
This repository has been archived by the owner on Jan 3, 2024. It is now read-only.

Commit

Permalink
Improve share type description in Avatar Group
Browse files Browse the repository at this point in the history
  • Loading branch information
pascalwengerter committed May 5, 2021
1 parent caf2f20 commit 3decf93
Show file tree
Hide file tree
Showing 7 changed files with 152 additions and 48 deletions.
8 changes: 8 additions & 0 deletions changelog/unreleased/enhancement-a11y-avatar
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Enhancement: Lazy img loading & accessibility for OcAvatar

- Add lazy loading to OcImg component
- Internalize former dependency vue-avatar into OcAvatar
- Make OcAvatar use OcImg component, using lazy loading
- Change OcAvatar to be a11y compliant (color contrasts, DOM structure)

https://github.com/owncloud/owncloud-design-system/pull/1282
2 changes: 0 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,6 @@
"uikit": "3.5.16",
"url-loader": "^4.1.1",
"vue": "^2.6.11",
"vue-avatar": "^2.2.0",
"vue-datetime": "^1.0.0-beta.10",
"vue-gettext": "^2.1.12",
"vue-inline-svg": "^2.0.0",
Expand Down Expand Up @@ -152,7 +151,6 @@
"tippy.js": "^6.3.1",
"uikit": "3.5.16",
"vue": "^2.6.11",
"vue-avatar": "^2.2.0",
"vue-datetime": "^1.0.0-beta.10",
"vue-inline-svg": "^2.0.0",
"vue-select": "^3.11.2",
Expand Down
10 changes: 9 additions & 1 deletion src/components/OcImage.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<img :src="src" :alt="alt" :aria-hidden="ariaHidden" :title="title" />
<img :src="src" :alt="alt" :aria-hidden="!alt" :title="title" />
</template>
<script>
/**
Expand Down Expand Up @@ -36,6 +36,14 @@ export default {
required: false,
default: null,
},
loadingType: {
type: String,
required: false,
default: "eager",
validator: value => {
return value.match(/(eager|lazy)/)
},
},
},
computed: {
ariaHidden() {
Expand Down
2 changes: 1 addition & 1 deletion src/components/__snapshots__/OcSidebar.spec.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ exports[`OcSidebar displays a logo image if its source is specified 1`] = `
<div class="oc-sidebar-content-wrapper">
<!---->
<router-link-stub tag="a" to="/" class="oc-sidebar-logo">
<oc-img-stub src="examples/placeholder_brand_logo.svg" alt="ownCloud" class="oc-sidebar-logo-img"></oc-img-stub>
<oc-img-stub src="examples/placeholder_brand_logo.svg" alt="ownCloud" loadingtype="eager" class="oc-sidebar-logo-img"></oc-img-stub>
</router-link-stub>
<!---->
<nav class="oc-sidebar-nav">
Expand Down
143 changes: 128 additions & 15 deletions src/components/avatars/OcAvatar.vue
Original file line number Diff line number Diff line change
@@ -1,31 +1,50 @@
<template>
<avatar
class="oc-avatar"
:username="userName"
:size="width"
:src="src"
<span
class="vue-avatar--wrapper oc-avatar"
:style="[style]"
:width="width"
:aria-label="accessibleLabel === '' ? null : accessibleLabel"
:aria-hidden="accessibleLabel === '' ? 'true' : null"
:focusable="accessibleLabel === '' ? 'false' : null"
:role="accessibleLabel === '' ? null : 'img'"
/>
>
<oc-img v-if="isImage" loading="lazy" class="avatarImg" :src="src" @error="onImgError" />
<span v-show="!isImage" class="avatarInitials">{{ userInitial }}</span>
</span>
</template>

<script>
import Avatar from "vue-avatar"
import OcImg from "../OcImage.vue"
/**
* Avatar is a thumbnail representing user or group
*/
const getInitials = userName => {
let parts = userName.split(/[ -]/)
let initials = ""
for (var i = 0; i < parts.length; i++) {
initials += parts[i].charAt(0)
}
if (initials.length > 3 && initials.search(/[A-Z]/) !== -1) {
initials = initials.replace(/[a-z]+/g, "")
}
initials = initials.substr(0, 3).toUpperCase()
return initials
}
export default {
name: "OcAvatar",
status: "review",
release: "1.0.0",
components: {
Avatar,
},
components: { OcImg },
props: {
/**
* Source of the avatar
* Source of the avatar img. If none is provided, the avatar's initials get rendered on a colorful background
*/
src: {
type: String,
Expand All @@ -48,18 +67,112 @@ export default {
required: false,
default: "",
},
/**
* The size of the avatar in pixels
*/
width: {
type: Number,
required: false,
default: 50,
},
},
data() {
return {
backgroundColors: [
"#b82015",
"#c21c53",
"#9C27B0",
"#673AB7",
"#3F51B5",
"#106892",
"#055c68",
"#009688",
"#1a761d",
"#476e1a",
"#636d0b",
"#8e5c11",
"#795548",
"#465a64",
],
imgError: false,
}
},
computed: {
background() {
if (!this.isImage) {
return this.randomBackgroundColor(this.userName.length, this.backgroundColors)
}
return ""
},
isImage() {
return !this.imgError && Boolean(this.src)
},
style() {
const style = {
width: `${this.width}px`,
height: `${this.width}px`,
lineHeight: `${this.width + Math.floor(this.width / 20)}px`,
}
const initialBackgroundAndFontStyle = {
backgroundColor: this.background,
font: `${Math.floor(this.width / 2.5)}px/${this.width}px Helvetica, Arial, sans-serif`,
color: "white",
}
Object.assign(style, initialBackgroundAndFontStyle)
return style
},
userInitial() {
if (!this.isImage) {
const initials = getInitials(this.userName)
return initials
}
return ""
},
},
mounted() {
if (!this.isImage) {
this.$emit("avatar-initials", this.userName, this.userInitial)
}
},
methods: {
onImgError() {
this.imgError = true
},
randomBackgroundColor(seed, colors) {
return colors[seed % colors.length]
},
},
}
</script>

<style lang="scss">
.oc-avatar {
font-weight: bold;
align-items: center;
justify-content: center;
text-align: center;
user-select: none;
display: flex;
border-radius: 50%;
.avatarImg {
width: 100%;
height: auto;
border-radius: 50%;
}
}
</style>

<docs>
```
<oc-avatar src="https://picsum.photos/50/50?image=1074" accessibleLabel="Lion" />
<oc-avatar userName="Bruce Lee" accessibleLabel="Lion" />
```js
<oc-avatar src="https://picsum.photos/50/50?image=1074" accessible-label="Lion" />
<oc-avatar user-name="Bruce Lee" accessible-label="Lion" />
```
</docs>
30 changes: 6 additions & 24 deletions src/components/table/__snapshots__/OcTableFiles.spec.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -53,19 +53,13 @@ exports[`OcTableFiles displays all fields 1`] = `
</td>
<td class="oc-td oc-table-cell oc-table-cell-align-right oc-table-cell-align-middle oc-table-cell-width-auto oc-text-nowrap oc-table-data-cell oc-table-data-cell-size"><span class="oc-resource-size">105.9 MB</span></td>
<td class="oc-td oc-table-cell oc-table-cell-align-right oc-table-cell-align-middle oc-table-cell-width-auto oc-text-nowrap oc-table-data-cell oc-table-data-cell-sharedWith">
<div class="oc-avatar-group oc-table-files-people oc-avatar-group-stacked">
<div class="vue-avatar--wrapper oc-avatar" style="display: flex; width: 30px; height: 30px; border-radius: 50%; line-height: 31px; font-weight: bold; align-items: center; justify-content: center; text-align: center; user-select: none;" aria-label="Bob" role="img"><img src="https://images.unsplash.com/photo-1610216705422-caa3fcb6d158?ixid=MXwxMjA3fDB8MHxzZWFyY2h8MTB8fGZhY2V8ZW58MHwyfDB8&amp;ixlib=rb-1.2.1&amp;auto=format&amp;fit=crop&amp;w=800&amp;q=60" style="display: none;"> <span style="display: none;"></span></div>
<div class="vue-avatar--wrapper oc-avatar" style="display: flex; width: 30px; height: 30px; border-radius: 50%; line-height: 31px; font-weight: bold; align-items: center; justify-content: center; text-align: center; user-select: none;" aria-label="Marie" role="img"><img src="https://images.unsplash.com/photo-1584308972272-9e4e7685e80f?ixid=MXwxMjA3fDB8MHxzZWFyY2h8Mzh8fGZhY2V8ZW58MHwyfDB8&amp;ixlib=rb-1.2.1&amp;auto=format&amp;fit=crop&amp;w=800&amp;q=60" style="display: none;"> <span style="display: none;"></span></div>
<div class="vue-avatar--wrapper oc-avatar" style="display: flex; width: 30px; height: 30px; border-radius: 50%; align-items: center; justify-content: center; text-align: center; user-select: none; background-color: rgb(63, 81, 181); font: sans-serif; color: rgb(143, 161, 255);" aria-label="John Richards Emperor of long names" role="img">
<!----> <span>J</span>
</div>
<div class="oc-avatar-group oc-table-files-people oc-avatar-group-stacked"><span width="30" aria-label="Bob" role="img" class="vue-avatar--wrapper oc-avatar" style="width: 30px; height: 30px; font: sans-serif; color: white;"><img src="https://images.unsplash.com/photo-1610216705422-caa3fcb6d158?ixid=MXwxMjA3fDB8MHxzZWFyY2h8MTB8fGZhY2V8ZW58MHwyfDB8&amp;ixlib=rb-1.2.1&amp;auto=format&amp;fit=crop&amp;w=800&amp;q=60" alt="" aria-hidden="true" loading="lazy" class="avatarImg"> <span class="avatarInitials" style="display: none;"></span></span><span width="30" aria-label="Marie" role="img" class="vue-avatar--wrapper oc-avatar" style="width: 30px; height: 30px; font: sans-serif; color: white;"><img src="https://images.unsplash.com/photo-1584308972272-9e4e7685e80f?ixid=MXwxMjA3fDB8MHxzZWFyY2h8Mzh8fGZhY2V8ZW58MHwyfDB8&amp;ixlib=rb-1.2.1&amp;auto=format&amp;fit=crop&amp;w=800&amp;q=60" alt="" aria-hidden="true" loading="lazy" class="avatarImg"> <span class="avatarInitials" style="display: none;"></span></span><span width="30" aria-label="John Richards Emperor of long names" role="img" class="vue-avatar--wrapper oc-avatar" style="width: 30px; height: 30px; background-color: rgb(63, 81, 181); font: sans-serif; color: white;"><!----> <span class="avatarInitials">J</span></span>
<!---->
<!---->
</div>
</td>
<td class="oc-td oc-table-cell oc-table-cell-align-right oc-table-cell-align-middle oc-table-cell-width-auto oc-text-nowrap oc-table-data-cell oc-table-data-cell-owner">
<div class="oc-avatar-group oc-table-files-people">
<div class="vue-avatar--wrapper oc-avatar" style="display: flex; width: 30px; height: 30px; border-radius: 50%; line-height: 31px; font-weight: bold; align-items: center; justify-content: center; text-align: center; user-select: none;" aria-label="Bob" role="img"><img src="https://images.unsplash.com/photo-1610216705422-caa3fcb6d158?ixid=MXwxMjA3fDB8MHxzZWFyY2h8MTB8fGZhY2V8ZW58MHwyfDB8&amp;ixlib=rb-1.2.1&amp;auto=format&amp;fit=crop&amp;w=800&amp;q=60" style="display: none;"> <span style="display: none;"></span></div>
<div class="oc-avatar-group oc-table-files-people"><span width="30" aria-label="Bob" role="img" class="vue-avatar--wrapper oc-avatar" style="width: 30px; height: 30px; font: sans-serif; color: white;"><img src="https://images.unsplash.com/photo-1610216705422-caa3fcb6d158?ixid=MXwxMjA3fDB8MHxzZWFyY2h8MTB8fGZhY2V8ZW58MHwyfDB8&amp;ixlib=rb-1.2.1&amp;auto=format&amp;fit=crop&amp;w=800&amp;q=60" alt="" aria-hidden="true" loading="lazy" class="avatarImg"> <span class="avatarInitials" style="display: none;"></span></span>
<!---->
<!---->
</div>
Expand Down Expand Up @@ -102,19 +96,13 @@ exports[`OcTableFiles displays all fields 1`] = `
</td>
<td class="oc-td oc-table-cell oc-table-cell-align-right oc-table-cell-align-middle oc-table-cell-width-auto oc-text-nowrap oc-table-data-cell oc-table-data-cell-size"><span class="oc-resource-size">?</span></td>
<td class="oc-td oc-table-cell oc-table-cell-align-right oc-table-cell-align-middle oc-table-cell-width-auto oc-text-nowrap oc-table-data-cell oc-table-data-cell-sharedWith">
<div class="oc-avatar-group oc-table-files-people oc-avatar-group-stacked">
<div class="vue-avatar--wrapper oc-avatar" style="display: flex; width: 30px; height: 30px; border-radius: 50%; line-height: 31px; font-weight: bold; align-items: center; justify-content: center; text-align: center; user-select: none;" aria-label="Bob" role="img"><img src="https://images.unsplash.com/photo-1610216705422-caa3fcb6d158?ixid=MXwxMjA3fDB8MHxzZWFyY2h8MTB8fGZhY2V8ZW58MHwyfDB8&amp;ixlib=rb-1.2.1&amp;auto=format&amp;fit=crop&amp;w=800&amp;q=60" style="display: none;"> <span style="display: none;"></span></div>
<div class="vue-avatar--wrapper oc-avatar" style="display: flex; width: 30px; height: 30px; border-radius: 50%; line-height: 31px; font-weight: bold; align-items: center; justify-content: center; text-align: center; user-select: none;" aria-label="Marie" role="img"><img src="https://images.unsplash.com/photo-1584308972272-9e4e7685e80f?ixid=MXwxMjA3fDB8MHxzZWFyY2h8Mzh8fGZhY2V8ZW58MHwyfDB8&amp;ixlib=rb-1.2.1&amp;auto=format&amp;fit=crop&amp;w=800&amp;q=60" style="display: none;"> <span style="display: none;"></span></div>
<div class="vue-avatar--wrapper oc-avatar" style="display: flex; width: 30px; height: 30px; border-radius: 50%; align-items: center; justify-content: center; text-align: center; user-select: none; background-color: rgb(63, 81, 181); font: sans-serif; color: rgb(143, 161, 255);" aria-label="John Richards Emperor of long names" role="img">
<!----> <span>J</span>
</div>
<div class="oc-avatar-group oc-table-files-people oc-avatar-group-stacked"><span width="30" aria-label="Bob" role="img" class="vue-avatar--wrapper oc-avatar" style="width: 30px; height: 30px; font: sans-serif; color: white;"><img src="https://images.unsplash.com/photo-1610216705422-caa3fcb6d158?ixid=MXwxMjA3fDB8MHxzZWFyY2h8MTB8fGZhY2V8ZW58MHwyfDB8&amp;ixlib=rb-1.2.1&amp;auto=format&amp;fit=crop&amp;w=800&amp;q=60" alt="" aria-hidden="true" loading="lazy" class="avatarImg"> <span class="avatarInitials" style="display: none;"></span></span><span width="30" aria-label="Marie" role="img" class="vue-avatar--wrapper oc-avatar" style="width: 30px; height: 30px; font: sans-serif; color: white;"><img src="https://images.unsplash.com/photo-1584308972272-9e4e7685e80f?ixid=MXwxMjA3fDB8MHxzZWFyY2h8Mzh8fGZhY2V8ZW58MHwyfDB8&amp;ixlib=rb-1.2.1&amp;auto=format&amp;fit=crop&amp;w=800&amp;q=60" alt="" aria-hidden="true" loading="lazy" class="avatarImg"> <span class="avatarInitials" style="display: none;"></span></span><span width="30" aria-label="John Richards Emperor of long names" role="img" class="vue-avatar--wrapper oc-avatar" style="width: 30px; height: 30px; background-color: rgb(63, 81, 181); font: sans-serif; color: white;"><!----> <span class="avatarInitials">J</span></span>
<!---->
<!---->
</div>
</td>
<td class="oc-td oc-table-cell oc-table-cell-align-right oc-table-cell-align-middle oc-table-cell-width-auto oc-text-nowrap oc-table-data-cell oc-table-data-cell-owner">
<div class="oc-avatar-group oc-table-files-people">
<div class="vue-avatar--wrapper oc-avatar" style="display: flex; width: 30px; height: 30px; border-radius: 50%; line-height: 31px; font-weight: bold; align-items: center; justify-content: center; text-align: center; user-select: none;" aria-label="Bob" role="img"><img src="https://images.unsplash.com/photo-1610216705422-caa3fcb6d158?ixid=MXwxMjA3fDB8MHxzZWFyY2h8MTB8fGZhY2V8ZW58MHwyfDB8&amp;ixlib=rb-1.2.1&amp;auto=format&amp;fit=crop&amp;w=800&amp;q=60" style="display: none;"> <span style="display: none;"></span></div>
<div class="oc-avatar-group oc-table-files-people"><span width="30" aria-label="Bob" role="img" class="vue-avatar--wrapper oc-avatar" style="width: 30px; height: 30px; font: sans-serif; color: white;"><img src="https://images.unsplash.com/photo-1610216705422-caa3fcb6d158?ixid=MXwxMjA3fDB8MHxzZWFyY2h8MTB8fGZhY2V8ZW58MHwyfDB8&amp;ixlib=rb-1.2.1&amp;auto=format&amp;fit=crop&amp;w=800&amp;q=60" alt="" aria-hidden="true" loading="lazy" class="avatarImg"> <span class="avatarInitials" style="display: none;"></span></span>
<!---->
<!---->
</div>
Expand Down Expand Up @@ -151,19 +139,13 @@ exports[`OcTableFiles displays all fields 1`] = `
</td>
<td class="oc-td oc-table-cell oc-table-cell-align-right oc-table-cell-align-middle oc-table-cell-width-auto oc-text-nowrap oc-table-data-cell oc-table-data-cell-size"><span class="oc-resource-size"></span></td>
<td class="oc-td oc-table-cell oc-table-cell-align-right oc-table-cell-align-middle oc-table-cell-width-auto oc-text-nowrap oc-table-data-cell oc-table-data-cell-sharedWith">
<div class="oc-avatar-group oc-table-files-people oc-avatar-group-stacked">
<div class="vue-avatar--wrapper oc-avatar" style="display: flex; width: 30px; height: 30px; border-radius: 50%; line-height: 31px; font-weight: bold; align-items: center; justify-content: center; text-align: center; user-select: none;" aria-label="Bob" role="img"><img src="https://images.unsplash.com/photo-1610216705422-caa3fcb6d158?ixid=MXwxMjA3fDB8MHxzZWFyY2h8MTB8fGZhY2V8ZW58MHwyfDB8&amp;ixlib=rb-1.2.1&amp;auto=format&amp;fit=crop&amp;w=800&amp;q=60" style="display: none;"> <span style="display: none;"></span></div>
<div class="vue-avatar--wrapper oc-avatar" style="display: flex; width: 30px; height: 30px; border-radius: 50%; line-height: 31px; font-weight: bold; align-items: center; justify-content: center; text-align: center; user-select: none;" aria-label="Marie" role="img"><img src="https://images.unsplash.com/photo-1584308972272-9e4e7685e80f?ixid=MXwxMjA3fDB8MHxzZWFyY2h8Mzh8fGZhY2V8ZW58MHwyfDB8&amp;ixlib=rb-1.2.1&amp;auto=format&amp;fit=crop&amp;w=800&amp;q=60" style="display: none;"> <span style="display: none;"></span></div>
<div class="vue-avatar--wrapper oc-avatar" style="display: flex; width: 30px; height: 30px; border-radius: 50%; align-items: center; justify-content: center; text-align: center; user-select: none; background-color: rgb(63, 81, 181); font: sans-serif; color: rgb(143, 161, 255);" aria-label="John Richards Emperor of long names" role="img">
<!----> <span>J</span>
</div>
<div class="oc-avatar-group oc-table-files-people oc-avatar-group-stacked"><span width="30" aria-label="Bob" role="img" class="vue-avatar--wrapper oc-avatar" style="width: 30px; height: 30px; font: sans-serif; color: white;"><img src="https://images.unsplash.com/photo-1610216705422-caa3fcb6d158?ixid=MXwxMjA3fDB8MHxzZWFyY2h8MTB8fGZhY2V8ZW58MHwyfDB8&amp;ixlib=rb-1.2.1&amp;auto=format&amp;fit=crop&amp;w=800&amp;q=60" alt="" aria-hidden="true" loading="lazy" class="avatarImg"> <span class="avatarInitials" style="display: none;"></span></span><span width="30" aria-label="Marie" role="img" class="vue-avatar--wrapper oc-avatar" style="width: 30px; height: 30px; font: sans-serif; color: white;"><img src="https://images.unsplash.com/photo-1584308972272-9e4e7685e80f?ixid=MXwxMjA3fDB8MHxzZWFyY2h8Mzh8fGZhY2V8ZW58MHwyfDB8&amp;ixlib=rb-1.2.1&amp;auto=format&amp;fit=crop&amp;w=800&amp;q=60" alt="" aria-hidden="true" loading="lazy" class="avatarImg"> <span class="avatarInitials" style="display: none;"></span></span><span width="30" aria-label="John Richards Emperor of long names" role="img" class="vue-avatar--wrapper oc-avatar" style="width: 30px; height: 30px; background-color: rgb(63, 81, 181); font: sans-serif; color: white;"><!----> <span class="avatarInitials">J</span></span>
<!---->
<!---->
</div>
</td>
<td class="oc-td oc-table-cell oc-table-cell-align-right oc-table-cell-align-middle oc-table-cell-width-auto oc-text-nowrap oc-table-data-cell oc-table-data-cell-owner">
<div class="oc-avatar-group oc-table-files-people">
<div class="vue-avatar--wrapper oc-avatar" style="display: flex; width: 30px; height: 30px; border-radius: 50%; line-height: 31px; font-weight: bold; align-items: center; justify-content: center; text-align: center; user-select: none;" aria-label="Bob" role="img"><img src="https://images.unsplash.com/photo-1610216705422-caa3fcb6d158?ixid=MXwxMjA3fDB8MHxzZWFyY2h8MTB8fGZhY2V8ZW58MHwyfDB8&amp;ixlib=rb-1.2.1&amp;auto=format&amp;fit=crop&amp;w=800&amp;q=60" style="display: none;"> <span style="display: none;"></span></div>
<div class="oc-avatar-group oc-table-files-people"><span width="30" aria-label="Bob" role="img" class="vue-avatar--wrapper oc-avatar" style="width: 30px; height: 30px; font: sans-serif; color: white;"><img src="https://images.unsplash.com/photo-1610216705422-caa3fcb6d158?ixid=MXwxMjA3fDB8MHxzZWFyY2h8MTB8fGZhY2V8ZW58MHwyfDB8&amp;ixlib=rb-1.2.1&amp;auto=format&amp;fit=crop&amp;w=800&amp;q=60" alt="" aria-hidden="true" loading="lazy" class="avatarImg"> <span class="avatarInitials" style="display: none;"></span></span>
<!---->
<!---->
</div>
Expand Down
Loading

0 comments on commit 3decf93

Please sign in to comment.