forked from DebaucheryLibrarian/traxxx
282 lines
5.2 KiB
Vue
282 lines
5.2 KiB
Vue
<template>
|
|
<div
|
|
class="notifications"
|
|
>
|
|
<div class="notifications-header">
|
|
<h4 class="notifications-title">Notifications</h4>
|
|
|
|
<div class="notifications-actions">
|
|
<Icon
|
|
v-if="unseenNotifications.length > 0"
|
|
v-tooltip="'Mark all as seen'"
|
|
icon="checkmark"
|
|
@click="checkNotifications"
|
|
/>
|
|
|
|
<Icon
|
|
icon="plus3"
|
|
@click="showAddAlert = true"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<AddAlert
|
|
v-if="showAddAlert"
|
|
@close="showAddAlert = false"
|
|
>Alert</AddAlert>
|
|
|
|
<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)"
|
|
>
|
|
<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"
|
|
:src="`/img/logos/${notification.scene.entity.slug}/favicon_${theme === 'dark' ? 'light' : 'dark'}.png`"
|
|
class="notification-favicon"
|
|
>
|
|
|
|
<img
|
|
v-else
|
|
: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">
|
|
<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="checkNotification(notification.id)"
|
|
/>
|
|
</router-link>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import AddAlert from '../alerts/add.vue';
|
|
|
|
function notifications() {
|
|
return this.$store.state.ui.notifications;
|
|
}
|
|
|
|
function unseenNotifications() {
|
|
return this.notifications.filter(notification => !notification.seen);
|
|
}
|
|
|
|
async function checkNotifications() {
|
|
await this.$store.dispatch('checkNotifications');
|
|
await this.$store.dispatch('fetchNotifications');
|
|
}
|
|
|
|
async function checkNotification(notificationId) {
|
|
await this.$store.dispatch('checkNotification', notificationId);
|
|
await this.$store.dispatch('fetchNotifications');
|
|
}
|
|
|
|
export default {
|
|
components: {
|
|
AddAlert,
|
|
},
|
|
data() {
|
|
return {
|
|
showAddAlert: false,
|
|
};
|
|
},
|
|
computed: {
|
|
notifications,
|
|
unseenNotifications,
|
|
},
|
|
methods: {
|
|
checkNotifications,
|
|
checkNotification,
|
|
},
|
|
};
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.notifications {
|
|
width: 30rem;
|
|
}
|
|
|
|
.notifications-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
|
|
.icon {
|
|
padding: .5rem;
|
|
fill: var(--shadow);
|
|
|
|
: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 {
|
|
box-shadow: 0 0 3px var(--shadow-weak);
|
|
}
|
|
|
|
.notifications-empty {
|
|
padding: .5rem 1rem;
|
|
color: var(--shadow);
|
|
}
|
|
|
|
.notification {
|
|
display: block;
|
|
margin: 0 0 -1px 0;
|
|
color: var(--text);
|
|
|
|
&.unseen {
|
|
border-right: solid .5rem var(--primary);
|
|
}
|
|
|
|
&:not(:last-child) {
|
|
.notification-body,
|
|
.notification-check {
|
|
border-bottom: solid 1px var(--shadow-hint);
|
|
}
|
|
}
|
|
|
|
&:hover {
|
|
color: var(--primary);
|
|
}
|
|
}
|
|
|
|
.notification-link {
|
|
display: flex;
|
|
align-items: stretch;
|
|
color: inherit;
|
|
text-decoration: none;
|
|
}
|
|
|
|
.notification-body {
|
|
flex-grow: 1;
|
|
padding: .4rem 1rem .25rem .5rem;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.notification-row {
|
|
display: flex;
|
|
align-items: center;
|
|
overflow: hidden;
|
|
|
|
&:not(:last-child) {
|
|
margin: 0 0 .1rem 0;
|
|
}
|
|
}
|
|
|
|
.notification-favicon {
|
|
width: 1rem;
|
|
height: 1rem;
|
|
margin: 0 .5rem 0 0;
|
|
}
|
|
|
|
.notification-actors {
|
|
height: 1.1rem;
|
|
display: inline-block;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.notification-tags {
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.notification-actor,
|
|
.notification-tag {
|
|
white-space: nowrap;
|
|
|
|
&:not(:last-child)::after {
|
|
content: ',';
|
|
padding: 0 .1rem 0 0;
|
|
}
|
|
}
|
|
|
|
.notification-actor {
|
|
color: var(--shadow-strong);
|
|
font-size: .9rem;
|
|
}
|
|
|
|
.notification-tag {
|
|
font-weight: bold;
|
|
}
|
|
|
|
.notification-check {
|
|
padding: 1rem;
|
|
fill: var(--shadow-weak);
|
|
|
|
&:hover {
|
|
fill: var(--primary);
|
|
}
|
|
}
|
|
|
|
.poster {
|
|
width: 5rem;
|
|
height: 3rem;
|
|
object-fit: cover;
|
|
object-position: center;
|
|
}
|
|
</style>
|