Skip to content

Commit

Permalink
Merge pull request #5059 from nextcloud-libraries/feat/user-status-icon
Browse files Browse the repository at this point in the history
feat: Add NcUserStatusIcon
  • Loading branch information
Pytal authored Jan 17, 2024
2 parents 07862b4 + 57c3eb6 commit b14fc59
Show file tree
Hide file tree
Showing 12 changed files with 255 additions and 61 deletions.
8 changes: 8 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,12 @@ module.exports = {
],
},
},
rules: {
'import/no-unresolved': [
'error',
{
ignore: ['\\?raw$'],
},
],
},
}
3 changes: 3 additions & 0 deletions l10n/messages.pot
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ msgstr ""
msgid "Boston Blue"
msgstr ""

msgid "busy"
msgstr ""

msgid "Cancel changes"
msgstr ""

Expand Down
5 changes: 4 additions & 1 deletion src/assets/status-icons/user-status-away.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 5 additions & 1 deletion src/assets/status-icons/user-status-dnd.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 4 additions & 1 deletion src/assets/status-icons/user-status-invisible.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 3 additions & 1 deletion src/assets/status-icons/user-status-online.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
30 changes: 7 additions & 23 deletions src/components/NcAvatar/NcAvatar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -167,10 +167,10 @@ export default {
<span v-if="showUserStatusIconOnAvatar" class="avatardiv__user-status avatardiv__user-status--icon">
{{ userStatus.icon }}
</span>
<NcIconSvgWrapper v-else-if="canDisplayUserStatus"
<NcUserStatusIcon v-else-if="canDisplayUserStatus"
class="avatardiv__user-status"
:svg="userStatusIcon"
:name="userStatusIconName" />
:status="userStatus.status"
:aria-hidden="String(hasMenu)" />

<!-- Show the letter if no avatar nor icon class -->
<span v-if="showInitials"
Expand All @@ -188,9 +188,9 @@ import NcActions from '../NcActions/index.js'
import NcActionLink from '../NcActionLink/index.js'
import NcButton from '../NcButton/index.js'
import NcLoadingIcon from '../NcLoadingIcon/index.js'
import NcIconSvgWrapper from '../NcIconSvgWrapper/index.js'
import NcUserStatusIcon from '../NcUserStatusIcon/index.js'
import usernameToColor from '../../functions/usernameToColor/index.js'
import { getUserStatusIcon, getUserStatusIconName, getUserStatusText } from '../../utils/UserStatus.ts'
import { getUserStatusText } from '../../utils/UserStatus.ts'
import { userStatus } from '../../mixins/index.js'
import { t } from '../../l10n.js'

Expand Down Expand Up @@ -238,7 +238,7 @@ export default {
NcActionLink,
NcButton,
NcLoadingIcon,
NcIconSvgWrapper,
NcUserStatusIcon,
},
mixins: [userStatus],
props: {
Expand Down Expand Up @@ -385,26 +385,10 @@ export default {
}
return t('Avatar of {displayName}', { displayName: this.displayName ?? this.user })
},

userStatusIcon() {
return getUserStatusIcon(this.userStatus.status)
},

/**
* If the avatar has no menu no aria-label is assigned, but for accessibility we still need the status to be accessible
* So this sets the required accessible label for the user status icon.
*/
userStatusIconName() {
// only needed if non-interactive, otherwise the aria-label is set
if (this.hasMenu) {
return
}
return getUserStatusIconName(this.userStatus.status)
},
canDisplayUserStatus() {
return this.showUserStatus
&& this.hasStatus
&& ['online', 'away', 'dnd'].includes(this.userStatus.status)
&& ['online', 'away', 'busy', 'dnd'].includes(this.userStatus.status)
},
showUserStatusIconOnAvatar() {
return this.showUserStatus
Expand Down
17 changes: 4 additions & 13 deletions src/components/NcRichContenteditable/NcAutoCompleteResult.vue
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,9 @@
class="autocomplete-result__status autocomplete-result__status--icon">
{{ status && status.icon || '' }}
</span>
<NcIconSvgWrapper v-else-if="status.status && status.status !== 'offline'"
<NcUserStatusIcon v-else-if="status.status && status.status !== 'offline'"
class="autocomplete-result__status"
:svg="userStatusIcon"
:name="userStatusIconName" />
:status="status.status" />
</div>

<!-- Title and subline -->
Expand All @@ -50,15 +49,13 @@
<script>
import { generateUrl } from '@nextcloud/router'

import NcIconSvgWrapper from '../NcIconSvgWrapper/index.js'

import { getUserStatusIcon, getUserStatusIconName } from '../../utils/UserStatus.ts'
import NcUserStatusIcon from '../NcUserStatusIcon/index.js'

export default {
name: 'NcAutoCompleteResult',

components: {
NcIconSvgWrapper,
NcUserStatusIcon,
},

props: {
Expand Down Expand Up @@ -101,12 +98,6 @@ export default {
? this.getAvatarUrl(this.id, 44)
: null
},
userStatusIcon() {
return getUserStatusIcon(this.status.status)
},
userStatusIconName() {
return getUserStatusIconName(this.status.status)
},
},

methods: {
Expand Down
191 changes: 191 additions & 0 deletions src/components/NcUserStatusIcon/NcUserStatusIcon.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
<!--
- @copyright 2024 Christopher Ng <chrng8@gmail.com>
-
- @author Christopher Ng <chrng8@gmail.com>
-
- @license AGPL-3.0-or-later
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as
- published by the Free Software Foundation, either version 3 of the
- License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-->

<docs>
### Description

This component displays a user status icon.

### Example

```vue
<template>
<div class="row">
<NcUserStatusIcon status="online" />
<NcUserStatusIcon status="away" />
<NcUserStatusIcon status="dnd" />
<NcUserStatusIcon status="invisible" />
</div>
</template>

<style>
.row {
display: flex;
gap: 10px;
}
</style>
```
</docs>

<template>
<span v-if="activeStatus"
class="user-status-icon"
:class="{
'user-status-icon--invisible': ['invisible', 'offline'].includes(status),
}"
role="img"
:aria-hidden="ariaHidden"
:aria-label="ariaLabel"
v-html="activeSvg" /> <!-- eslint-disable-line vue/no-v-html -->
</template>

<script>
import Vue from 'vue'
import axios from '@nextcloud/axios'
import { generateOcsUrl } from '@nextcloud/router'
import { getCapabilities } from '@nextcloud/capabilities'

import onlineSvg from '../../assets/status-icons/user-status-online.svg?raw'
import awaySvg from '../../assets/status-icons/user-status-away.svg?raw'
import dndSvg from '../../assets/status-icons/user-status-dnd.svg?raw'
import invisibleSvg from '../../assets/status-icons/user-status-invisible.svg?raw'

import { getUserStatusText } from '../../utils/UserStatus.ts'
import { t } from '../../l10n.js'

export default {
name: 'NcUserStatusIcon',

props: {
/**
* Set the user id to fetch the status
*/
user: {
type: String,
default: null,
},

/**
* Set the status
*
* @type {'online' | 'away' | 'busy' | 'dnd' | 'invisible' | 'offline'}
*/
status: {
type: String,
default: null,
validator: (value) => [
'online',
'away',
'busy',
'dnd',
'invisible',
'offline',
].includes(value),
},

/**
* Set the `aria-hidden` attribute
*
* @type {'true' | 'false'}
*/
ariaHidden: {
type: String,
default: null,
validator: (value) => [
'true',
'false',
].includes(value),
},
},

data() {
return {
fetchedUserStatus: null,
}
},

computed: {
activeStatus() {
return this.status ?? this.fetchedUserStatus
},

activeSvg() {
const matchSvg = {
online: onlineSvg,
away: awaySvg,
busy: awaySvg,
dnd: dndSvg,
invisible: invisibleSvg,
offline: invisibleSvg,
}
return matchSvg[this.activeStatus] ?? null
},

ariaLabel() {
if (this.ariaHidden === 'true') {
return null
}
return t('User status: {status}', { status: getUserStatusText(this.activeStatus) })
},
},

watch: {
user: {
immediate: true,
async handler(user, _oldUser) {
if (!user || !getCapabilities()?.user_status?.enabled) {
this.fetchedUserStatus = null
return
}
try {
const { data } = await axios.get(generateOcsUrl('/apps/user_status/api/v1/statuses/{user}', { user }))
this.fetchedUserStatus = data.ocs?.data?.status
} catch (error) {
this.fetchedUserStatus = null
}
},
},
},

mounted() {
if (!this.user && !this.status) {
Vue.util.warn('[NcUserStatusIcon] The `user` or `status` prop should be set.')
}
},
}
</script>

<style lang="scss" scoped>
.user-status-icon {
display: flex;
justify-content: center;
align-items: center;
min-width: 16px;
min-height: 16px;
max-width: 20px;
max-height: 20px;

&--invisible {
filter: var(--background-invert-if-dark);
}
}
</style>
23 changes: 23 additions & 0 deletions src/components/NcUserStatusIcon/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* @copyright 2024 Christopher Ng <chrng8@gmail.com>
*
* @author Christopher Ng <chrng8@gmail.com>
*
* @license AGPL-3.0-or-later
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

export { default } from './NcUserStatusIcon.vue'
1 change: 1 addition & 0 deletions src/components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,4 +92,5 @@ export { default as NcSettingsSelectGroup } from './NcSettingsSelectGroup/index.
export { default as NcTextField } from './NcTextField/index.js'
export { default as NcTimezonePicker } from './NcTimezonePicker/index.js'
export { default as NcUserBubble } from './NcUserBubble/index.js'
export { default as NcUserStatusIcon } from './NcUserStatusIcon/index.js'
export { default as NcTextArea } from './NcTextArea/index.js'
Loading

0 comments on commit b14fc59

Please sign in to comment.