aboutsummaryrefslogtreecommitdiffstats
path: root/core/src/components/AppMenuIcon.vue
diff options
context:
space:
mode:
Diffstat (limited to 'core/src/components/AppMenuIcon.vue')
-rw-r--r--core/src/components/AppMenuIcon.vue63
1 files changed, 63 insertions, 0 deletions
diff --git a/core/src/components/AppMenuIcon.vue b/core/src/components/AppMenuIcon.vue
new file mode 100644
index 00000000000..bdf14cdd0d7
--- /dev/null
+++ b/core/src/components/AppMenuIcon.vue
@@ -0,0 +1,63 @@
+<!--
+ - SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
+ - SPDX-License-Identifier: AGPL-3.0-or-later
+ -->
+
+<template>
+ <span class="app-menu-icon"
+ role="img"
+ :aria-hidden="ariaHidden"
+ :aria-label="ariaLabel">
+ <img class="app-menu-icon__icon" :src="app.icon">
+ <IconDot v-if="app.unread" class="app-menu-icon__unread" :size="10" />
+ </span>
+</template>
+
+<script setup lang="ts">
+import type { INavigationEntry } from '../types/navigation'
+import { n } from '@nextcloud/l10n'
+import { computed } from 'vue'
+
+import IconDot from 'vue-material-design-icons/Circle.vue'
+
+const props = defineProps<{
+ app: INavigationEntry
+}>()
+
+const ariaHidden = computed(() => String(props.app.unread > 0))
+
+const ariaLabel = computed(() => {
+ if (ariaHidden.value === 'true') {
+ return ''
+ }
+ return props.app.name
+ + (props.app.unread > 0 ? ` (${n('core', '{count} notification', '{count} notifications', props.app.unread, { count: props.app.unread })})` : '')
+})
+</script>
+
+<style scoped lang="scss">
+$icon-size: 20px;
+$unread-indicator-size: 10px;
+
+.app-menu-icon {
+ box-sizing: border-box;
+ position: relative;
+
+ height: $icon-size;
+ width: $icon-size;
+
+ &__icon {
+ transition: margin 0.1s ease-in-out;
+ height: $icon-size;
+ width: $icon-size;
+ filter: var(--background-image-invert-if-bright);
+ }
+
+ &__unread {
+ color: var(--color-error);
+ position: absolute;
+ inset-block-end: calc($unread-indicator-size / -2.5);
+ inset-inline-end: calc($unread-indicator-size / -2.5);
+ }
+}
+</style>