<template> <div class="notifications"> <div class="notifications-header"> <h4 class="notifications-title">Notifications</h4> <div class="notifications-actions"> <Icon v-if="unseenCount > 0" v-tooltip="'Mark all as seen'" icon="checkmark" @click="checkNotifications" /> <Icon v-tooltip="'Add alert'" icon="plus3" @click="$emit('addAlert')" /> </div> </div> <div class="notifications-body"> <div v-if="notifications.length === 0" class="notifications-empty" >No notifications</div> <ul v-else class="nolist" > <li v-for="notification in notifications" :key="`notification-${notification.id}`" :class="{ unseen: !notification.seen }" class="notification" @click="checkNotification(notification.id, true)" > <router-link :to="`/scene/${notification.scene.id}/${notification.scene.slug}`" class="notification-link" > <img :src="getPath(notification.scene.poster, 'thumbnail')" class="poster" > <div class="notification-body"> <div class="notification-row notification-title"> <img v-if="notification.scene.entity.type === 'network' || notification.scene.entity.independent" v-tooltip="notification.scene.entity.name" :src="`/img/logos/${notification.scene.entity.slug}/favicon_${theme === 'dark' ? 'light' : 'dark'}.png`" class="notification-favicon" > <img v-else v-tooltip="notification.scene.entity.name" :src="`/img/logos/${notification.scene.entity.parent.slug}/favicon_${theme === 'dark' ? 'light' : 'dark'}.png`" class="notification-favicon" > New <ul v-if="notification.alert?.tags.length > 0" class="nolist notification-tags" > <li v-for="tag in notification.alert.tags" :key="`notification-tag-${tag.slug}`" class="notification-tag" >{{ tag.name }}</li> </ul>scene </div> <div class="notification-row notification-details"> <span class="notification-date">{{ formatDate(notification.scene.date, 'MMM D') }}</span> <ul v-if="notification.scene.actors.length > 0" class="nolist notification-actors" > <li v-for="actor in notification.scene.actors" :key="`notification-actor-${actor.slug}`" class="notification-actor" >{{ actor.name }}</li> </ul> </div> </div> <Icon v-if="!notification.seen" v-tooltip="'Mark as seen'" icon="checkmark" class="notification-check" @click.prevent.stop="checkNotification(notification.id)" /> <Icon v-if="notification.alert" v-tooltip="`You set an alert for <strong>${notification.alert.tags.map(tag => tag.name).join(', ') || 'all'}</strong> scenes with <strong>${notification.alert.actors.map(actor => actor.name).join(', ') || 'any actor'}</strong> for <strong>${notification.alert.entity?.name || 'any channel'}</strong>`" icon="question5" @click.prevent.stop /> </router-link> </li> </ul> </div> <div @click="events.emit('blur')"> <router-link to="/notifications" class="notification-link notification-more" >See all</router-link> </div> </div> </template> <script> async function checkNotifications() { await this.$store.dispatch('checkNotifications'); this.$emit('check'); } async function checkNotification(notificationId, blur) { await this.$store.dispatch('checkNotification', notificationId); this.$emit('check'); if (blur) { this.events.emit('blur'); } } export default { props: { notifications: { type: Array, default: () => [], }, unseenCount: { type: Number, default: 0, }, }, data() { return { showAddAlert: false, }; }, emits: ['addAlert'], methods: { checkNotifications, checkNotification, }, }; </script> <style lang="scss" scoped> .notifications { width: 30rem; max-height: calc(100vh - 5rem); display: flex; flex-direction: column; } .notifications-header { display: flex; justify-content: space-between; .icon { padding: .5rem; fill: var(--shadow); &:first-child { padding: .5rem .5rem .5rem 1.5rem; } &:last-child { padding: .5rem 1.5rem .5rem .5rem; } &:hover { fill: var(--primary); cursor: pointer; } } } .notifications-title { display: inline-block; padding: .5rem 1rem; margin: 0; color: var(--shadow); font-size: 1rem; font-weight: bold; } .notifications-body { flex-grow: 1; overflow-y: auto; box-shadow: 0 0 3px var(--shadow-weak); } .notifications-empty { padding: .5rem 1rem; color: var(--shadow); } .notification { display: block; border-right: solid .5rem var(--shadow-touch); color: var(--text); &.unseen { border-right: solid .5rem var(--primary); } .icon { padding: 1.3rem .5rem; fill: var(--shadow-weak); &.notification-check { padding: 1.3rem .5rem 1.3rem 1rem; } &:last-child { padding: 1.3rem 1rem 1.3rem .5rem; } &:hover { fill: var(--primary); } } &:not(:last-child) { border-bottom: solid 1px var(--shadow-hint); margin: 0 0 -1px 0; } &:hover { background: var(--shadow-touch); &:not(.unseen) { border-right: solid .5rem var(--shadow-weak); } } } .notification-link { display: flex; align-items: stretch; color: inherit; text-decoration: none; } .notification-body { flex-grow: 1; padding: .4rem 0 0 0; overflow: hidden; } .notification-row { display: flex; overflow: hidden; } .notification-title { margin: .15rem .5rem .3rem .5rem; } .notification-favicon { width: 1rem; height: 1rem; margin: 0 .5rem 0 0; } .notification-tags { white-space: nowrap; } .notification-actors { padding: 0 .5rem; height: 1.25rem; display: inline-block; overflow: hidden; } .notification-date { width: 3rem; flex-shrink: 0; padding: .25rem .25rem .35rem .25rem; border-right: solid 1px var(--shadow-hint); border-top: solid 1px var(--shadow-hint); color: var(--shadow-strong); font-size: .8rem; text-align: center; } .notification-actor, .notification-tag { white-space: nowrap; &:not(:last-child)::after { content: ','; padding: 0 .1rem 0 0; } } .notification-actor { padding: .25rem .15rem .35rem 0; color: var(--shadow-strong); font-size: .9rem; } .notification-tag { font-weight: bold; } .notification-more { display: block; padding: .5rem 1rem; color: var(--shadow); text-align: center; font-size: .9rem; font-weight: bold; &:hover { color: var(--primary); } } .poster { width: 6rem; height: 3.6rem; object-fit: cover; object-position: center; } </style>