Compare commits
3 Commits
837fc98ad2
...
7f25846d55
Author | SHA1 | Date |
---|---|---|
|
7f25846d55 | |
|
d36e52d5d1 | |
|
da0cbced15 |
|
@ -0,0 +1,438 @@
|
|||
<template>
|
||||
<Dialog
|
||||
title="Add alert"
|
||||
@close="$emit('close')"
|
||||
>
|
||||
<form
|
||||
class="dialog-body"
|
||||
@submit.prevent="addAlert"
|
||||
>
|
||||
<div class="dialog-section">
|
||||
<h3 class="dialog-heading">
|
||||
When<span class="dialog-description">All to appear in the same scene</span>
|
||||
</h3>
|
||||
|
||||
<div class="alert-section">
|
||||
<h4
|
||||
v-if="actors.length > 1"
|
||||
class="alert-heading"
|
||||
>Actors</h4>
|
||||
|
||||
<h4
|
||||
v-else
|
||||
class="alert-heading"
|
||||
>Actor</h4>
|
||||
|
||||
<ul class="actors nolist">
|
||||
<li
|
||||
v-for="actor in actors"
|
||||
:key="`actor-${actor.id}`"
|
||||
class="actor"
|
||||
>
|
||||
<ActorPreview :actor="actor" />
|
||||
|
||||
<Icon
|
||||
icon="cross3"
|
||||
class="remove"
|
||||
@click.native="removeActor(actor)"
|
||||
/>
|
||||
</li>
|
||||
|
||||
<Tooltip>
|
||||
<li class="actor placeholder"><template v-if="actors.length === 0">Any actor</template>
|
||||
<Icon
|
||||
icon="plus3"
|
||||
class="add"
|
||||
/>
|
||||
</li>
|
||||
|
||||
<template v-slot:tooltip>
|
||||
<Search
|
||||
content="actors"
|
||||
@select="actor => addActor(actor)"
|
||||
/>
|
||||
</template>
|
||||
</Tooltip>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="alert-section">
|
||||
<h4
|
||||
v-if="actors.length > 1"
|
||||
class="alert-heading"
|
||||
>Do</h4>
|
||||
|
||||
<h4
|
||||
v-else
|
||||
class="alert-heading"
|
||||
>Does</h4>
|
||||
|
||||
<ul class="tags nolist">
|
||||
<li
|
||||
v-for="tag in tags"
|
||||
:key="`tag-${tag.id}`"
|
||||
class="tag"
|
||||
>{{ tag.name }}
|
||||
<Icon
|
||||
icon="cross3"
|
||||
class="remove"
|
||||
@click.native="removeTag(tag)"
|
||||
/>
|
||||
</li>
|
||||
|
||||
<Tooltip>
|
||||
<li class="tag placeholder"><template v-if="tags.length === 0">Any type of scene</template>
|
||||
<Icon
|
||||
icon="plus3"
|
||||
class="add"
|
||||
/>
|
||||
</li>
|
||||
|
||||
<template v-slot:tooltip>
|
||||
<Search
|
||||
content="tags"
|
||||
:defaults="['anal', 'blowbang', 'mfm', 'dp', 'gangbang', 'airtight']"
|
||||
@select="tag => addTag(tag)"
|
||||
/>
|
||||
</template>
|
||||
</Tooltip>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="alert-section">
|
||||
<h4 class="alert-heading">For</h4>
|
||||
|
||||
<div class="entities">
|
||||
<div
|
||||
v-if="entity"
|
||||
class="entity"
|
||||
>
|
||||
<Entity :entity="entity" />
|
||||
|
||||
<Icon
|
||||
icon="cross3"
|
||||
class="remove"
|
||||
@click.native="removeEntity(entity)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Tooltip v-if="!entity">
|
||||
<div class="entity placeholder">
|
||||
Any channel
|
||||
|
||||
<Icon
|
||||
icon="plus3"
|
||||
class="add"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<template v-slot:tooltip>
|
||||
<Search
|
||||
label="Search channels"
|
||||
content="entities"
|
||||
@select="entity => addEntity(entity)"
|
||||
/>
|
||||
</template>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="dialog-section">
|
||||
<h3 class="dialog-heading">Then</h3>
|
||||
|
||||
<label class="alert-label">
|
||||
<Checkbox
|
||||
:checked="notify"
|
||||
@change="checked => notify = checked"
|
||||
/>Notify me in traxxx
|
||||
</label>
|
||||
|
||||
<label class="alert-label">
|
||||
<Checkbox
|
||||
:checked="email"
|
||||
@change="checked => email = checked"
|
||||
/>Send me an e-mail
|
||||
</label>
|
||||
|
||||
<div class="stashes-container">
|
||||
<ul class="stashes nolist">
|
||||
<li
|
||||
v-for="stash in stashes"
|
||||
:key="`stash-${stash.id}`"
|
||||
class="stash"
|
||||
>{{ stash.name }}
|
||||
|
||||
<Icon
|
||||
icon="cross3"
|
||||
class="remove"
|
||||
@click.native="removeStash(stash)"
|
||||
/>
|
||||
</li>
|
||||
|
||||
<Tooltip>
|
||||
<li class="stash placeholder">
|
||||
Add to stash
|
||||
<Icon
|
||||
icon="plus3"
|
||||
class="add"
|
||||
/>
|
||||
</li>
|
||||
|
||||
<template v-slot:tooltip>
|
||||
<Search
|
||||
content="stashes"
|
||||
@select="stash => addStash(stash)"
|
||||
/>
|
||||
</template>
|
||||
</Tooltip>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="dialog-actions right">
|
||||
<button
|
||||
type="submit"
|
||||
class="button button-primary"
|
||||
>Add alert</button>
|
||||
</div>
|
||||
</form>
|
||||
</Dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ActorPreview from '../actors/preview.vue';
|
||||
import Entity from '../entities/tile.vue';
|
||||
import Checkbox from '../form/checkbox.vue';
|
||||
import Search from './search.vue';
|
||||
|
||||
async function addAlert() {
|
||||
await this.$store.dispatch('addAlert', {
|
||||
actors: this.actors.map(actor => actor.id),
|
||||
tags: this.tags.map(tag => tag.id),
|
||||
entity: this.entity?.id,
|
||||
notify: this.notify,
|
||||
email: this.email,
|
||||
stashes: this.stashes.map(stash => stash.id),
|
||||
});
|
||||
|
||||
this.$emit('close', true);
|
||||
}
|
||||
|
||||
function addActor(actor) {
|
||||
if (!this.actors.some(selectedActor => selectedActor.id === actor.id)) {
|
||||
this.actors = this.actors.concat(actor);
|
||||
}
|
||||
|
||||
this.events.emit('blur');
|
||||
}
|
||||
|
||||
function addEntity(entity) {
|
||||
this.entity = entity;
|
||||
this.events.emit('blur');
|
||||
}
|
||||
|
||||
function addTag(tag) {
|
||||
if (!this.tags.some(selectedTag => selectedTag.id === tag.id)) {
|
||||
this.tags = this.tags.concat(tag);
|
||||
}
|
||||
|
||||
this.events.emit('blur');
|
||||
}
|
||||
|
||||
function removeActor(actor) {
|
||||
this.actors = this.actors.filter(listedActor => listedActor.id !== actor.id);
|
||||
}
|
||||
|
||||
function removeEntity() {
|
||||
this.entity = null;
|
||||
}
|
||||
|
||||
function removeTag(tag) {
|
||||
this.tags = this.tags.filter(listedTag => listedTag.id !== tag.id);
|
||||
}
|
||||
|
||||
function addStash(stash) {
|
||||
if (!this.stashes.some(selectedStash => selectedStash.id === stash.id)) {
|
||||
this.stashes = this.stashes.concat(stash);
|
||||
}
|
||||
|
||||
this.events.emit('blur');
|
||||
}
|
||||
|
||||
function removeStash(stash) {
|
||||
this.stashes = this.stashes.filter(listedStash => listedStash.id !== stash.id);
|
||||
}
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ActorPreview,
|
||||
Checkbox,
|
||||
Entity,
|
||||
Search,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
actors: [],
|
||||
tags: [],
|
||||
entity: null,
|
||||
notify: true,
|
||||
email: false,
|
||||
stashes: [],
|
||||
availableStashes: this.$store.state.auth.user.stashes,
|
||||
};
|
||||
},
|
||||
emits: ['close'],
|
||||
methods: {
|
||||
addActor,
|
||||
addAlert,
|
||||
addEntity,
|
||||
addTag,
|
||||
addStash,
|
||||
removeActor,
|
||||
removeEntity,
|
||||
removeTag,
|
||||
removeStash,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.dialog-section {
|
||||
width: 30rem;
|
||||
max-width: 100%;
|
||||
|
||||
&:first-child {
|
||||
border-bottom: solid 1px var(--shadow-hint);
|
||||
margin: 0 0 1rem 0;
|
||||
}
|
||||
}
|
||||
|
||||
.dialog-heading {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin: 0 0 .25rem 0;
|
||||
color: var(--primary);
|
||||
}
|
||||
|
||||
.dialog-description {
|
||||
color: var(--shadow);
|
||||
font-size: .9rem;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.alert-heading {
|
||||
margin: .75rem 0 .25rem 0;
|
||||
}
|
||||
|
||||
.actors,
|
||||
.entities,
|
||||
.tags {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
font-size: 0;
|
||||
}
|
||||
|
||||
.actors > .actor,
|
||||
.entity,
|
||||
.tag,
|
||||
.stash {
|
||||
position: relative;
|
||||
font-size: 1rem;
|
||||
margin: 0 .5rem .5rem 0;
|
||||
}
|
||||
|
||||
.entity .tile {
|
||||
width: 10rem;
|
||||
height: 2.5rem;
|
||||
}
|
||||
|
||||
.tag:not(.placeholder),
|
||||
.stash:not(.placeholder) {
|
||||
padding: .5rem .75rem;
|
||||
border: solid 1px var(--shadow-hint);
|
||||
margin: 0 .75rem 0 0;
|
||||
font-size: .9rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.stashes {
|
||||
margin: 0 0 0 .25rem;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.remove {
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
position: absolute;
|
||||
top: -.35rem;
|
||||
right: -.35rem;
|
||||
z-index: 1;
|
||||
border: solid 1px var(--darken-hint);
|
||||
border-radius: 50%;
|
||||
background: var(--background);
|
||||
fill: var(--shadow-weak);
|
||||
box-shadow: 0 0 1px var(--shadow);
|
||||
|
||||
&:hover {
|
||||
fill: var(--text-light);
|
||||
background: var(--primary);
|
||||
border: solid 1px var(--primary);
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.placeholder {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
color: var(--shadow-strong);
|
||||
padding: .75rem 0;
|
||||
margin: 0 0 .5rem 0;
|
||||
font-size: 1rem;
|
||||
|
||||
.add {
|
||||
fill: var(--shadow);
|
||||
margin: 0 0 0 .5rem;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: var(--primary);
|
||||
cursor: pointer;
|
||||
|
||||
.add {
|
||||
fill: var(--primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.alert-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: .5rem 0;
|
||||
margin: 0 0 .25rem 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.stashes-heading {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 0 0 .5rem 0;
|
||||
font-size: 1rem;
|
||||
|
||||
.alert-label {
|
||||
display: inline-block;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.tooltip-container {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.check-container {
|
||||
display: inline-block;
|
||||
margin: 0 .5rem 0 0;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,41 @@
|
|||
<template>
|
||||
<Dialog
|
||||
title="Remove alert"
|
||||
@close="$emit('close', false)"
|
||||
>
|
||||
<form
|
||||
class="dialog-body"
|
||||
@submit.prevent="removeAlert"
|
||||
>
|
||||
Are you sure you want to remove alert?
|
||||
|
||||
<div class="dialog-actions right">
|
||||
<button
|
||||
type="submit"
|
||||
class="button button-primary"
|
||||
>Remove</button>
|
||||
</div>
|
||||
</form>
|
||||
</Dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
async function removeAlert() {
|
||||
await this.$store.dispatch('removeAlert', this.alert.id);
|
||||
|
||||
this.$emit('close', true);
|
||||
}
|
||||
|
||||
export default {
|
||||
props: {
|
||||
alert: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
emits: ['close'],
|
||||
methods: {
|
||||
removeAlert,
|
||||
},
|
||||
};
|
||||
</script>
|
|
@ -0,0 +1,126 @@
|
|||
<template>
|
||||
<div>
|
||||
<input
|
||||
ref="input"
|
||||
v-model="query"
|
||||
:placeholder="label || `Search ${content}`"
|
||||
class="input"
|
||||
@input="search"
|
||||
>
|
||||
|
||||
<ul
|
||||
v-if="results.length > 0"
|
||||
class="nolist"
|
||||
>
|
||||
<li
|
||||
v-for="actor in results"
|
||||
:key="`actor-${actor.id}`"
|
||||
class="result"
|
||||
@click="selectResult(actor)"
|
||||
><img
|
||||
v-if="actor.avatar"
|
||||
:src="getPath(actor.avatar)"
|
||||
class="avatar"
|
||||
>{{ actor.name }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
async function search() {
|
||||
if (this.content === 'actors') {
|
||||
this.results = await this.$store.dispatch('searchActors', {
|
||||
query: this.query,
|
||||
minLength: 1,
|
||||
limit: 10,
|
||||
});
|
||||
}
|
||||
|
||||
if (this.content === 'entities') {
|
||||
this.results = await this.$store.dispatch('searchEntities', {
|
||||
query: this.query,
|
||||
limit: 10,
|
||||
});
|
||||
}
|
||||
|
||||
if (this.content === 'tags') {
|
||||
this.results = await this.$store.dispatch('searchTags', {
|
||||
query: this.query,
|
||||
minLength: 1,
|
||||
limit: 10,
|
||||
});
|
||||
}
|
||||
|
||||
if (this.content === 'stashes') {
|
||||
this.results = this.$store.state.auth.user.stashes.filter(stash => new RegExp(this.query).test(stash.name));
|
||||
}
|
||||
}
|
||||
|
||||
function selectResult(item) {
|
||||
this.query = null;
|
||||
this.results = [];
|
||||
|
||||
this.$emit('select', item);
|
||||
}
|
||||
|
||||
async function mounted() {
|
||||
this.$refs.input.focus();
|
||||
|
||||
if (this.defaults.length > 0 && this.content === 'tags') {
|
||||
this.results = await this.$store.dispatch('fetchTags', {
|
||||
slugs: this.defaults,
|
||||
});
|
||||
}
|
||||
|
||||
if (this.content === 'stashes') {
|
||||
this.results = this.$store.state.auth.user.stashes;
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
props: {
|
||||
content: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
defaults: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
query: null,
|
||||
results: [],
|
||||
};
|
||||
},
|
||||
emits: ['select'],
|
||||
mounted,
|
||||
methods: {
|
||||
search,
|
||||
selectResult,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.result {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: .5rem;
|
||||
|
||||
&:hover {
|
||||
color: var(--primary);
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.avatar {
|
||||
height: 2rem;
|
||||
margin: 0 .5rem 0 0;
|
||||
}
|
||||
</style>
|
|
@ -6,7 +6,7 @@
|
|||
>
|
||||
<div
|
||||
class="dialog"
|
||||
@click.stop
|
||||
@click.stop="events.emit('blur')"
|
||||
>
|
||||
<div
|
||||
v-if="title || $slots.header"
|
||||
|
@ -98,14 +98,29 @@ export default {
|
|||
}
|
||||
|
||||
.body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
overflow: hidden;
|
||||
|
||||
::v-deep(.section) {
|
||||
padding: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep(.dialog-body) {
|
||||
padding: 1rem;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
::v-deep(.dialog-section:not(:last-child)) {
|
||||
border-bottom: solid 1px var(--shadow-hint);
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
::v-deep(.dialog-actions) {
|
||||
display: flex;
|
||||
padding: 1rem 0 0 0;
|
||||
margin: 1rem 0 0 0;
|
||||
|
||||
&.center {
|
||||
justify-content: center;
|
||||
|
|
|
@ -47,6 +47,7 @@ export default {
|
|||
|
||||
.tile {
|
||||
width: 15rem;
|
||||
height: 6rem;
|
||||
}
|
||||
|
||||
&.expanded {
|
||||
|
|
|
@ -56,7 +56,7 @@ export default {
|
|||
@import 'theme';
|
||||
|
||||
.tile {
|
||||
height: 6rem;
|
||||
height: 100%;
|
||||
background: var(--tile);
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
title="Filters"
|
||||
@close="$emit('close')"
|
||||
>
|
||||
<div class="filters">
|
||||
<div class="filters dialog-body">
|
||||
<h3 class="form-heading">Show me</h3>
|
||||
|
||||
<ul class="tags nolist">
|
||||
|
@ -47,7 +47,7 @@ export default {
|
|||
},
|
||||
data() {
|
||||
return {
|
||||
tags: ['anal', 'gay', 'transsexual', 'bisexual', 'pissing'],
|
||||
tags: ['anal', 'gay', 'transsexual', 'bisexual', 'pissing', 'anal prolapse'],
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
|
|
@ -82,8 +82,25 @@
|
|||
@click.stop="$emit('toggleSidebar')"
|
||||
><Icon icon="menu" /></div>
|
||||
|
||||
<Tooltip v-if="me">
|
||||
<div
|
||||
class="header-button header-notifications"
|
||||
@click="showAddAlert = true"
|
||||
>
|
||||
<Icon
|
||||
icon="bell2"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<template v-slot:tooltip>
|
||||
<div
|
||||
class="notifications"
|
||||
>No notifications</div>
|
||||
</template>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip>
|
||||
<div class="header-account">
|
||||
<div class="header-button header-account">
|
||||
<div class="account">
|
||||
<Icon
|
||||
icon="user3-long"
|
||||
|
@ -121,6 +138,11 @@
|
|||
/>
|
||||
</template>
|
||||
</Tooltip>
|
||||
|
||||
<AddAlert
|
||||
v-if="showAddAlert"
|
||||
@close="showAddAlert = false"
|
||||
>Alert</AddAlert>
|
||||
</div>
|
||||
</header>
|
||||
</template>
|
||||
|
@ -128,11 +150,18 @@
|
|||
<script>
|
||||
import Menu from './menu.vue';
|
||||
import Search from './search.vue';
|
||||
import AddAlert from '../alerts/add.vue';
|
||||
|
||||
import logo from '../../img/logo.svg';
|
||||
|
||||
function me() {
|
||||
return this.$store.state.auth.user;
|
||||
}
|
||||
|
||||
export default {
|
||||
AddAlert,
|
||||
components: {
|
||||
AddAlert,
|
||||
Menu,
|
||||
Search,
|
||||
},
|
||||
|
@ -142,8 +171,12 @@ export default {
|
|||
logo,
|
||||
searching: false,
|
||||
showFilters: false,
|
||||
showAddAlert: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
me,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
|
@ -257,26 +290,12 @@ export default {
|
|||
}
|
||||
}
|
||||
|
||||
.header-toggles {
|
||||
margin: 0 .5rem 0 0;
|
||||
.header-button {
|
||||
padding: 1rem .75rem;
|
||||
|
||||
.icon {
|
||||
padding: 1rem .75rem;
|
||||
fill: var(--shadow);
|
||||
|
||||
&:hover {
|
||||
fill: var(--shadow-strong);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&.active {
|
||||
fill: var(--primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.header-account {
|
||||
padding: 1rem;
|
||||
.icon {
|
||||
fill: var(--shadow);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
|
@ -285,12 +304,20 @@ export default {
|
|||
border-color: var(--primary);
|
||||
}
|
||||
|
||||
.avatar {
|
||||
.icon {
|
||||
fill: var(--primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.header-account {
|
||||
padding: 1rem 1rem 1rem .75rem;
|
||||
}
|
||||
|
||||
.header-notifications {
|
||||
padding: 1rem .75rem 1rem 1rem;
|
||||
}
|
||||
|
||||
.account {
|
||||
width: 1.25rem;
|
||||
height: 1.25rem;
|
||||
|
@ -333,6 +360,10 @@ export default {
|
|||
}
|
||||
}
|
||||
|
||||
.notifications {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
@media(max-width: $breakpoint-kilo) {
|
||||
.search-full {
|
||||
display: none;
|
||||
|
@ -364,7 +395,8 @@ export default {
|
|||
display: none;
|
||||
}
|
||||
|
||||
.header-account {
|
||||
.header-account,
|
||||
.header-notifications {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -144,6 +144,10 @@ export default {
|
|||
grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
|
||||
grid-gap: .5rem;
|
||||
padding: 1rem 0;
|
||||
|
||||
.tile {
|
||||
height: 6rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media(max-width: $breakpoint2) {
|
||||
|
|
|
@ -16,10 +16,17 @@
|
|||
|
||||
<div class="scene-footer">
|
||||
<img
|
||||
v-if="scene.entity.parent"
|
||||
:src="`/img/logos/${scene.entity.parent.slug}/favicon_light.png`"
|
||||
class="scene-favicon"
|
||||
>
|
||||
|
||||
<img
|
||||
v-else
|
||||
:src="`/img/logos/${scene.entity.slug}/favicon_light.png`"
|
||||
class="scene-favicon"
|
||||
>
|
||||
|
||||
<span class="scene-title">{{ scene.title }}</span>
|
||||
</div>
|
||||
</a>
|
|
@ -3,7 +3,10 @@
|
|||
title="Add stash"
|
||||
@close="$emit('close', false)"
|
||||
>
|
||||
<form @submit.prevent="addStash">
|
||||
<form
|
||||
class="dialog-body"
|
||||
@submit.prevent="addStash"
|
||||
>
|
||||
<input
|
||||
ref="name"
|
||||
v-model="name"
|
|
@ -3,7 +3,10 @@
|
|||
title="Remove stash"
|
||||
@close="$emit('close', false)"
|
||||
>
|
||||
<form @submit.prevent="removeStash">
|
||||
<form
|
||||
class="dialog-body"
|
||||
@submit.prevent="removeStash"
|
||||
>
|
||||
Are you sure you want to remove stash "{{ stash.name }}"?
|
||||
|
||||
<div class="dialog-actions right">
|
|
@ -78,7 +78,7 @@
|
|||
<script>
|
||||
import Actor from '../actors/tile.vue';
|
||||
import Releases from '../releases/releases.vue';
|
||||
import RemoveStash from './remove-stash.vue';
|
||||
import RemoveStash from './remove.vue';
|
||||
import Toggle from '../form/toggle.vue';
|
||||
|
||||
async function fetchStash() {
|
||||
|
|
|
@ -117,7 +117,6 @@ function mounted() {
|
|||
});
|
||||
|
||||
this.events.on('scroll', () => {
|
||||
console.log('scroll!');
|
||||
this.calculate();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -0,0 +1,249 @@
|
|||
<template>
|
||||
<div class="alert">
|
||||
<div class="alert-section alert-header">
|
||||
<div class="alert-targets">
|
||||
<Icon
|
||||
v-if="alert.notify"
|
||||
icon="bell2"
|
||||
class="alert-action"
|
||||
/>
|
||||
|
||||
<Icon
|
||||
v-if="alert.email"
|
||||
icon="envelop"
|
||||
class="alert-action"
|
||||
/>
|
||||
|
||||
<Icon
|
||||
v-if="alert.stashes?.length > 0"
|
||||
v-tooltip="alert.stashes.map(stash => stash.name).join()"
|
||||
icon="heart7"
|
||||
class="alert-action"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<span class="header-actions noselect">
|
||||
<Icon
|
||||
v-if="isMe"
|
||||
icon="bin"
|
||||
class="alert-remove"
|
||||
@click.native="showRemoveAlert = true"
|
||||
/>
|
||||
|
||||
<RemoveAlert
|
||||
v-if="showRemoveAlert"
|
||||
:alert="alert"
|
||||
@close="removeAlert"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="alert-triggers">
|
||||
<div
|
||||
v-if="alert.actors?.length > 0"
|
||||
class="alert-section alert-trigger"
|
||||
>
|
||||
<h4
|
||||
v-if="alert.actors.length > 1"
|
||||
class="alert-heading"
|
||||
>Actors</h4>
|
||||
|
||||
<h4
|
||||
v-else
|
||||
class="alert-heading"
|
||||
>Actor</h4>
|
||||
|
||||
<ul class="alert-actors nolist">
|
||||
<li
|
||||
v-for="actor in alert.actors"
|
||||
:key="`actor-${actor.id}`"
|
||||
class="alert-actor"
|
||||
>
|
||||
<ActorPreview
|
||||
:actor="actor"
|
||||
:alert="alert"
|
||||
/>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="alert.tags?.length > 0"
|
||||
class="alert-section alert-trigger"
|
||||
>
|
||||
<h4
|
||||
v-if="alert.tags.length > 1"
|
||||
class="alert-heading"
|
||||
>Tags</h4>
|
||||
|
||||
<h4
|
||||
v-else
|
||||
class="alert-heading"
|
||||
>Tag</h4>
|
||||
|
||||
<ul class="alert-tags nolist">
|
||||
<li
|
||||
v-for="tag in alert.tags"
|
||||
:key="`tag-${tag.id}`"
|
||||
><router-link
|
||||
:to="`/tag/${tag.slug}`"
|
||||
class="tag nolink"
|
||||
>{{ tag.name }}</router-link></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="alert-section alert-trigger">
|
||||
<h4 class="alert-heading">Channel</h4>
|
||||
|
||||
<Entity
|
||||
v-if="alert.entity"
|
||||
:entity="alert.entity"
|
||||
class="entity"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ActorPreview from '../actors/preview.vue';
|
||||
import RemoveAlert from '../alerts/remove.vue';
|
||||
import Entity from '../entities/tile.vue';
|
||||
|
||||
async function removeAlert(removed) {
|
||||
this.showRemoveAlert = false;
|
||||
|
||||
if (removed) {
|
||||
this.$emit('remove');
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ActorPreview,
|
||||
Entity,
|
||||
RemoveAlert,
|
||||
},
|
||||
props: {
|
||||
alert: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
isMe: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
emits: ['remove'],
|
||||
data() {
|
||||
return {
|
||||
showRemoveAlert: false,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
removeAlert,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.alert {
|
||||
min-width: 0;
|
||||
height: 100%;
|
||||
background: var(--background);
|
||||
box-shadow: 0 0 3px var(--darken-weak);
|
||||
}
|
||||
|
||||
.alert-header {
|
||||
border-bottom: solid 1px var(--shadow-hint);
|
||||
}
|
||||
|
||||
.alert-section {
|
||||
display: inline-block;
|
||||
padding: .5rem;
|
||||
}
|
||||
|
||||
.alert-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: stretch;
|
||||
padding: 0;
|
||||
|
||||
.alert-action {
|
||||
padding: .5rem;
|
||||
fill: var(--shadow);
|
||||
}
|
||||
}
|
||||
|
||||
.alert-triggers {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.alert-heading {
|
||||
display: block;
|
||||
padding: 0 .5rem .5rem 0;
|
||||
margin: 0;
|
||||
color: var(--shadow-strong);
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
font-size: .9rem;
|
||||
}
|
||||
|
||||
.alert-more {
|
||||
flex-shrink: 0;
|
||||
margin: 0 0 0 .5rem;
|
||||
color: var(--shadow);
|
||||
font-size: .9rem;
|
||||
}
|
||||
|
||||
.header-actions {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.alert-remove {
|
||||
height: auto;
|
||||
padding: 0 .5rem 0 .75rem;
|
||||
fill: var(--shadow);
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
fill: var(--shadow-strong);
|
||||
}
|
||||
}
|
||||
|
||||
.alert-triggers {
|
||||
dislay: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.alert-trigger {
|
||||
flex-shrink: 0;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.alert-actors,
|
||||
.alert-tags {
|
||||
display: flex;
|
||||
grid-gap: .5rem;
|
||||
}
|
||||
|
||||
.tag {
|
||||
color: var(--shadow-strong);
|
||||
padding: .5rem;
|
||||
border: solid 1px var(--shadow-hint);
|
||||
font-size: .9rem;
|
||||
font-weight: bold;
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
border: solid 1px var(--primary);
|
||||
}
|
||||
}
|
||||
|
||||
.entity {
|
||||
width: 10rem;
|
||||
height: 2.5rem;
|
||||
}
|
||||
</style>
|
|
@ -82,9 +82,9 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import ActorPreview from './actor-preview.vue';
|
||||
import ScenePreview from './scene-preview.vue';
|
||||
import RemoveStash from '../stashes/remove-stash.vue';
|
||||
import ActorPreview from '../actors/preview.vue';
|
||||
import ScenePreview from '../releases/scene-preview.vue';
|
||||
import RemoveStash from '../stashes/remove.vue';
|
||||
import Toggle from '../form/toggle.vue';
|
||||
|
||||
async function publishStash(isPublic) {
|
||||
|
|
|
@ -43,18 +43,61 @@
|
|||
<Icon icon="plus2" />
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<AddStash
|
||||
v-if="showAddStash"
|
||||
@close="closeAddStash"
|
||||
/>
|
||||
</section>
|
||||
|
||||
<AddStash
|
||||
v-if="showAddStash"
|
||||
@close="closeAddStash"
|
||||
/>
|
||||
<section
|
||||
v-if="user.alerts?.length > 0"
|
||||
class="section"
|
||||
>
|
||||
<div class="section-header">
|
||||
<h3 class="section-heading">Alerts</h3>
|
||||
|
||||
<Icon
|
||||
icon="plus3"
|
||||
class="header-add"
|
||||
@click="showAddAlert = true"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<ul class="section-body alerts nolist">
|
||||
<li
|
||||
v-for="alert in user.alerts"
|
||||
:key="`alert-${alert.id}`"
|
||||
class="alert"
|
||||
>
|
||||
<Alert
|
||||
:alert="alert"
|
||||
:is-me="isMe"
|
||||
@remove="() => fetchUser()"
|
||||
/>
|
||||
</li>
|
||||
|
||||
<li
|
||||
class="alerts-add"
|
||||
@click="showAddAlert = true"
|
||||
>
|
||||
<Icon icon="plus2" />
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<AddAlert
|
||||
v-if="showAddAlert"
|
||||
@close="closeAddAlert"
|
||||
>Alert</AddAlert>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Stash from './stash.vue';
|
||||
import AddStash from '../stashes/add-stash.vue';
|
||||
import Alert from './alert.vue';
|
||||
import AddStash from '../stashes/add.vue';
|
||||
import AddAlert from '../alerts/add.vue';
|
||||
|
||||
async function fetchUser() {
|
||||
this.user = await this.$store.dispatch('fetchUser', this.$route.params.username);
|
||||
|
@ -71,13 +114,23 @@ async function closeAddStash(addedStash) {
|
|||
}
|
||||
}
|
||||
|
||||
async function closeAddAlert(addedAlert) {
|
||||
this.showAddAlert = false;
|
||||
|
||||
if (addedAlert) {
|
||||
await this.fetchUser();
|
||||
}
|
||||
}
|
||||
|
||||
async function mounted() {
|
||||
await this.fetchUser();
|
||||
}
|
||||
|
||||
export default {
|
||||
components: {
|
||||
AddAlert,
|
||||
AddStash,
|
||||
Alert,
|
||||
Stash,
|
||||
},
|
||||
data() {
|
||||
|
@ -88,10 +141,12 @@ export default {
|
|||
isMe: false,
|
||||
pageTitle: null,
|
||||
showAddStash: false,
|
||||
showAddAlert: false,
|
||||
};
|
||||
},
|
||||
mounted,
|
||||
methods: {
|
||||
closeAddAlert,
|
||||
closeAddStash,
|
||||
fetchUser,
|
||||
},
|
||||
|
@ -122,7 +177,8 @@ export default {
|
|||
margin: 0 0 1rem 0;
|
||||
}
|
||||
|
||||
.stashes {
|
||||
.stashes,
|
||||
.alerts {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-auto-rows: 15fr;
|
||||
|
@ -162,7 +218,8 @@ export default {
|
|||
min-width: 0;
|
||||
}
|
||||
|
||||
.stashes-add {
|
||||
.stashes-add,
|
||||
.alerts-add {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
@ -186,7 +243,8 @@ export default {
|
|||
}
|
||||
|
||||
@media(max-width: $breakpoint-kilo) {
|
||||
.stashes {
|
||||
.stashes,
|
||||
.alerts {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
<!-- Generated by IcoMoon.io -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<title>alarm-add</title>
|
||||
<path d="M8 2c-3.866 0-7 3.134-7 7s3.134 7 7 7 7-3.134 7-7-3.134-7-7-7zM8 14.625c-3.107 0-5.625-2.518-5.625-5.625s2.518-5.625 5.625-5.625c3.107 0 5.625 2.518 5.625 5.625s-2.518 5.625-5.625 5.625zM14.606 4.487c0.251-0.438 0.394-0.946 0.394-1.487 0-1.657-1.343-3-3-3-0.966 0-1.825 0.457-2.374 1.166 2.061 0.426 3.831 1.644 4.98 3.322v0zM6.374 1.166c-0.549-0.709-1.408-1.166-2.374-1.166-1.657 0-3 1.343-3 3 0 0.541 0.143 1.049 0.394 1.487 1.148-1.678 2.919-2.896 4.98-3.322z"></path>
|
||||
<path d="M11 8h-2v-2h-2v2h-2v2h2v2h2v-2h2z"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 696 B |
|
@ -0,0 +1,6 @@
|
|||
<!-- Generated by IcoMoon.io -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<title>alarm-cancel</title>
|
||||
<path d="M8 2c-3.866 0-7 3.134-7 7s3.134 7 7 7 7-3.134 7-7-3.134-7-7-7zM8 14.625c-3.107 0-5.625-2.518-5.625-5.625s2.518-5.625 5.625-5.625c3.107 0 5.625 2.518 5.625 5.625s-2.518 5.625-5.625 5.625zM14.606 4.487c0.251-0.438 0.394-0.946 0.394-1.487 0-1.657-1.343-3-3-3-0.966 0-1.825 0.457-2.374 1.166 2.061 0.426 3.831 1.644 4.98 3.322v0zM6.374 1.166c-0.549-0.709-1.408-1.166-2.374-1.166-1.657 0-3 1.343-3 3 0 0.541 0.143 1.049 0.394 1.487 1.148-1.678 2.919-2.896 4.98-3.322z"></path>
|
||||
<path d="M11.457 11.043l-1.414 1.414-2.043-2.043-2.043 2.043-1.414-1.414 2.043-2.043-2.043-2.043 1.414-1.414 2.043 2.043 2.043-2.043 1.414 1.414-2.043 2.043 2.043 2.043z"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 826 B |
|
@ -0,0 +1,6 @@
|
|||
<!-- Generated by IcoMoon.io -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<title>alarm-check</title>
|
||||
<path d="M8 2c-3.866 0-7 3.134-7 7s3.134 7 7 7 7-3.134 7-7-3.134-7-7-7zM8 14.625c-3.107 0-5.625-2.518-5.625-5.625s2.518-5.625 5.625-5.625c3.107 0 5.625 2.518 5.625 5.625s-2.518 5.625-5.625 5.625zM14.606 4.487c0.251-0.438 0.394-0.946 0.394-1.487 0-1.657-1.343-3-3-3-0.966 0-1.825 0.457-2.374 1.166 2.061 0.426 3.831 1.644 4.98 3.322v0zM6.374 1.166c-0.549-0.709-1.408-1.166-2.374-1.166-1.657 0-3 1.343-3 3 0 0.541 0.143 1.049 0.394 1.487 1.148-1.678 2.919-2.896 4.98-3.322z"></path>
|
||||
<path d="M11 6.5l-4 4-1.5-1.5-1 1 2.5 2.5 5-5z"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 702 B |
|
@ -0,0 +1,6 @@
|
|||
<!-- Generated by IcoMoon.io -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<title>alarm</title>
|
||||
<path d="M8 2c-3.866 0-7 3.134-7 7s3.134 7 7 7 7-3.134 7-7-3.134-7-7-7zM8 14.625c-3.107 0-5.625-2.518-5.625-5.625s2.518-5.625 5.625-5.625c3.107 0 5.625 2.518 5.625 5.625s-2.518 5.625-5.625 5.625zM14.606 4.487c0.251-0.438 0.394-0.946 0.394-1.487 0-1.657-1.343-3-3-3-0.966 0-1.825 0.457-2.374 1.166 2.061 0.426 3.831 1.644 4.98 3.322v0zM6.374 1.166c-0.549-0.709-1.408-1.166-2.374-1.166-1.657 0-3 1.343-3 3 0 0.541 0.143 1.049 0.394 1.487 1.148-1.678 2.919-2.896 4.98-3.322z"></path>
|
||||
<path d="M8 9v-4h-1v5h4v-1z"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 677 B |
|
@ -0,0 +1,5 @@
|
|||
<!-- Generated by IcoMoon.io -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<title>bell-check</title>
|
||||
<path d="M16 13c-1.657 0-3-1.343-3-3v-4.455c0-2.199-1.718-4.033-4-4.454v-1.091h-2v1.091c-2.282 0.421-4 2.255-4 4.454v4.455c0 1.657-1.343 3-3 3v1h6.712c-0.081 0.178-0.127 0.377-0.127 0.586 0 0.781 0.633 1.414 1.414 1.414s1.414-0.633 1.414-1.414c0-0.209-0.045-0.407-0.127-0.586h6.713v-1zM7 11.559l-2.42-3.201 0.747-0.747 1.674 1.205 3.83-3.392 0.778 0.778-4.608 5.358z"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 540 B |
|
@ -0,0 +1,5 @@
|
|||
<!-- Generated by IcoMoon.io -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<title>bell-cross</title>
|
||||
<path d="M16 13c-1.657 0-3-1.343-3-3v-4.455c0-2.199-1.718-4.033-4-4.454v-1.091h-2v1.091c-2.282 0.421-4 2.255-4 4.454v4.455c0 1.657-1.343 3-3 3v1h6.712c-0.081 0.178-0.127 0.377-0.127 0.586 0 0.781 0.633 1.414 1.414 1.414s1.414-0.633 1.414-1.414c0-0.209-0.045-0.407-0.127-0.586h6.713v-1zM11 9.5l-1 1-2-2-2 2-1-1 2-2-2-2 1-1 2 2 2-2 1 1-2 2 2 2z"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 516 B |
|
@ -0,0 +1,5 @@
|
|||
<!-- Generated by IcoMoon.io -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<title>bell-minus</title>
|
||||
<path d="M16 13c-1.657 0-3-1.343-3-3v-4.455c0-2.199-1.718-4.033-4-4.454v-1.091h-2v1.091c-2.282 0.421-4 2.255-4 4.454v4.455c0 1.657-1.343 3-3 3v1h6.712c-0.081 0.178-0.127 0.377-0.127 0.586 0 0.781 0.633 1.414 1.414 1.414s1.414-0.633 1.414-1.414c0-0.209-0.045-0.407-0.127-0.586h6.713v-1zM11 9h-6v-2h6v2z"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 475 B |
|
@ -0,0 +1,5 @@
|
|||
<!-- Generated by IcoMoon.io -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<title>bell-plus</title>
|
||||
<path d="M16 13c-1.657 0-3-1.343-3-3v-4.455c0-2.199-1.718-4.033-4-4.454v-1.091h-2v1.091c-2.282 0.421-4 2.255-4 4.454v4.455c0 1.657-1.343 3-3 3v1h6.712c-0.081 0.178-0.127 0.377-0.127 0.586 0 0.781 0.633 1.414 1.414 1.414s1.414-0.633 1.414-1.414c0-0.209-0.045-0.407-0.127-0.586h6.713v-1zM11 9h-2v2h-2v-2h-2v-2h2v-2h2v2h2v2z"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 494 B |
|
@ -0,0 +1,5 @@
|
|||
<!-- Generated by IcoMoon.io -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<title>bell</title>
|
||||
<path d="M16.023 12.5c0-4.5-4-3.5-4-7 0-0.29-0.028-0.538-0.079-0.749-0.263-1.766-1.44-3.183-2.965-3.615 0.014-0.062 0.021-0.125 0.021-0.191 0-0.52-0.45-0.945-1-0.945s-1 0.425-1 0.945c0 0.065 0.007 0.129 0.021 0.191-1.71 0.484-2.983 2.208-3.020 4.273-0.001 0.030-0.001 0.060-0.001 0.091 0 3.5-4 2.5-4 7 0 1.191 2.665 2.187 6.234 2.439 0.336 0.631 1.001 1.061 1.766 1.061s1.43-0.43 1.766-1.061c3.568-0.251 6.234-1.248 6.234-2.439 0-0.004-0-0.007-0-0.011l0.024 0.011zM12.91 13.345c-0.847 0.226-1.846 0.389-2.918 0.479-0.089-1.022-0.947-1.824-1.992-1.824s-1.903 0.802-1.992 1.824c-1.072-0.090-2.071-0.253-2.918-0.479-1.166-0.311-1.724-0.659-1.928-0.845 0.204-0.186 0.762-0.534 1.928-0.845 1.356-0.362 3.1-0.561 4.91-0.561s3.554 0.199 4.91 0.561c1.166 0.311 1.724 0.659 1.928 0.845-0.204 0.186-0.762 0.534-1.928 0.845z"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 981 B |
|
@ -0,0 +1,5 @@
|
|||
<!-- Generated by IcoMoon.io -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<title>bell2</title>
|
||||
<path d="M16 13c-1.657 0-3-1.343-3-3v-4.455c0-2.199-1.718-4.033-4-4.454v-1.091h-2v1.091c-2.282 0.421-4 2.255-4 4.454v4.455c0 1.657-1.343 3-3 3v1h6.712c-0.081 0.178-0.127 0.377-0.127 0.586 0 0.781 0.633 1.414 1.414 1.414s1.414-0.633 1.414-1.414c0-0.209-0.045-0.407-0.127-0.586h6.713v-1z"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 454 B |
|
@ -0,0 +1,7 @@
|
|||
<!-- Generated by IcoMoon.io -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<title>bell3</title>
|
||||
<path d="M16 13c-1.657 0-3-1.343-3-3v-4.455c0-2.199-1.718-4.033-4-4.454v-1.091h-2v1.091c-2.282 0.421-4 2.255-4 4.454v4.455c0 1.657-1.343 3-3 3v1h6.712c-0.081 0.178-0.127 0.377-0.127 0.586 0 0.781 0.633 1.414 1.414 1.414s1.414-0.633 1.414-1.414c0-0.209-0.045-0.407-0.127-0.586h6.713v-1z"></path>
|
||||
<path d="M15.483 6c-0.261 0-0.481-0.203-0.498-0.467-0.118-1.787-0.908-3.444-2.226-4.666-0.202-0.188-0.214-0.504-0.027-0.707s0.504-0.214 0.707-0.027c1.506 1.397 2.409 3.291 2.543 5.334 0.018 0.276-0.191 0.514-0.466 0.532-0.011 0.001-0.022 0.001-0.033 0.001z"></path>
|
||||
<path d="M0.517 6c-0.011 0-0.022-0-0.033-0.001-0.276-0.018-0.484-0.256-0.466-0.532 0.134-2.043 1.038-3.937 2.543-5.334 0.203-0.188 0.519-0.176 0.707 0.027s0.176 0.519-0.027 0.707c-1.318 1.222-2.108 2.879-2.226 4.666-0.017 0.264-0.237 0.467-0.498 0.467z"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 982 B |
|
@ -0,0 +1,6 @@
|
|||
<!-- Generated by IcoMoon.io -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<title>calendar-day</title>
|
||||
<path d="M8 9c-0.553 0-1-0.447-1-1s0.447-1 1-1 1 0.447 1 1-0.447 1-1 1z"></path>
|
||||
<path d="M14 2v-2h-2v2h-8v-2h-2v2h-2v14h16v-14h-2zM3 15h-2v-2h2v2zM3 12h-2v-2h2v2zM3 9h-2v-2h2v2zM3 6h-2v-2h2v2zM6 15h-2v-2h2v2zM6 12h-2v-2h2v2zM6 9h-2v-2h2v2zM6 6h-2v-2h2v2zM9 15h-2v-2h2v2zM9 12h-2v-2h2v2zM9 9h-2v-2h2v2zM9 6h-2v-2h2v2zM12 15h-2v-2h2v2zM12 12h-2v-2h2v2zM12 9h-2v-2h2v2zM12 6h-2v-2h2v2zM15 15h-2v-2h2v2zM15 12h-2v-2h2v2zM15 9h-2v-2h2v2zM15 6h-2v-2h2v2z"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 625 B |
|
@ -0,0 +1,5 @@
|
|||
<!-- Generated by IcoMoon.io -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<title>calendar-empty</title>
|
||||
<path d="M14 2v-2h-2v2h-8v-2h-2v2h-2v14h16v-14h-2zM3 15h-2v-2h2v2zM3 12h-2v-2h2v2zM3 9h-2v-2h2v2zM3 6h-2v-2h2v2zM6 15h-2v-2h2v2zM6 12h-2v-2h2v2zM6 9h-2v-2h2v2zM6 6h-2v-2h2v2zM9 15h-2v-2h2v2zM9 12h-2v-2h2v2zM9 9h-2v-2h2v2zM9 6h-2v-2h2v2zM12 15h-2v-2h2v2zM12 12h-2v-2h2v2zM12 9h-2v-2h2v2zM12 6h-2v-2h2v2zM15 15h-2v-2h2v2zM15 12h-2v-2h2v2zM15 9h-2v-2h2v2zM15 6h-2v-2h2v2z"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 546 B |
|
@ -0,0 +1,6 @@
|
|||
<!-- Generated by IcoMoon.io -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<title>calendar-week</title>
|
||||
<path d="M8 9c-0.553 0-1-0.447-1-1s0.447-1 1-1 1 0.447 1 1-0.447 1-1 1zM12 8c0-0.553-0.447-1-1-1s-1 0.447-1 1 0.447 1 1 1 1-0.447 1-1zM15 8c0-0.553-0.447-1-1-1s-1 0.447-1 1 0.447 1 1 1 1-0.447 1-1zM6 8c0-0.553-0.447-1-1-1s-1 0.447-1 1 0.447 1 1 1 1-0.447 1-1zM3 8c0-0.553-0.447-1-1-1s-1 0.447-1 1 0.447 1 1 1 1-0.447 1-1z"></path>
|
||||
<path d="M14 2v-2h-2v2h-8v-2h-2v2h-2v14h16v-14h-2zM3 15h-2v-2h2v2zM3 12h-2v-2h2v2zM3 9h-2v-2h2v2zM3 6h-2v-2h2v2zM6 15h-2v-2h2v2zM6 12h-2v-2h2v2zM6 9h-2v-2h2v2zM6 6h-2v-2h2v2zM9 15h-2v-2h2v2zM9 12h-2v-2h2v2zM9 9h-2v-2h2v2zM9 6h-2v-2h2v2zM12 15h-2v-2h2v2zM12 12h-2v-2h2v2zM12 9h-2v-2h2v2zM12 6h-2v-2h2v2zM15 15h-2v-2h2v2zM15 12h-2v-2h2v2zM15 9h-2v-2h2v2zM15 6h-2v-2h2v2z"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 876 B |
|
@ -0,0 +1,35 @@
|
|||
<!-- Generated by IcoMoon.io -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<title>calendar3</title>
|
||||
<path d="M8 7h1v1h-1v-1z"></path>
|
||||
<path d="M10 9h1v1h-1v-1z"></path>
|
||||
<path d="M10 11h1v1h-1v-1z"></path>
|
||||
<path d="M8 5h1v1h-1v-1z"></path>
|
||||
<path d="M8 9h1v1h-1v-1z"></path>
|
||||
<path d="M8 13h1v1h-1v-1z"></path>
|
||||
<path d="M8 11h1v1h-1v-1z"></path>
|
||||
<path d="M6 5h1v1h-1v-1z"></path>
|
||||
<path d="M12 9h1v1h-1v-1z"></path>
|
||||
<path d="M12 7h1v1h-1v-1z"></path>
|
||||
<path d="M12 5h1v1h-1v-1z"></path>
|
||||
<path d="M12 11h1v1h-1v-1z"></path>
|
||||
<path d="M10 5h1v1h-1v-1z"></path>
|
||||
<path d="M12 13h1v1h-1v-1z"></path>
|
||||
<path d="M10 7h1v1h-1v-1z"></path>
|
||||
<path d="M10 13h1v1h-1v-1z"></path>
|
||||
<path d="M2 7h1v1h-1v-1z"></path>
|
||||
<path d="M2 9h1v1h-1v-1z"></path>
|
||||
<path d="M4 13h1v1h-1v-1z"></path>
|
||||
<path d="M6 7h1v1h-1v-1z"></path>
|
||||
<path d="M2 13h1v1h-1v-1z"></path>
|
||||
<path d="M2 11h1v1h-1v-1z"></path>
|
||||
<path d="M2 5h1v1h-1v-1z"></path>
|
||||
<path d="M6 11h1v1h-1v-1z"></path>
|
||||
<path d="M4 11h1v1h-1v-1z"></path>
|
||||
<path d="M6 9h1v1h-1v-1z"></path>
|
||||
<path d="M6 13h1v1h-1v-1z"></path>
|
||||
<path d="M4 5h1v1h-1v-1z"></path>
|
||||
<path d="M4 9h1v1h-1v-1z"></path>
|
||||
<path d="M4 7h1v1h-1v-1z"></path>
|
||||
<path d="M12 1v-1h-2v1h-5v-1h-2v1h-3v15h15v-15h-3zM10 2h2v1h-2v-1zM3 2h2v1h-2v-1zM14 15h-13v-11h13v11z"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 1.3 KiB |
|
@ -0,0 +1,5 @@
|
|||
<!-- Generated by IcoMoon.io -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<title>calendar5</title>
|
||||
<path d="M14 2h-1.5v0.5c0 0.551-0.449 1-1 1s-1-0.449-1-1v-0.5h-5v0.5c0 0.551-0.449 1-1 1s-1-0.449-1-1v-0.5h-1.5c-0.55 0-1 0.45-1 1v11c0 0.55 0.45 1 1 1h12c0.55 0 1-0.45 1-1v-11c0-0.55-0.45-1-1-1zM14 13.998c-0.001 0.001-0.001 0.001-0.002 0.002h-11.996c-0.001-0.001-0.001-0.001-0.002-0.002v-8.998h12v8.998zM4.5 3c0.276 0 0.5-0.224 0.5-0.5v-2c0-0.276-0.224-0.5-0.5-0.5s-0.5 0.224-0.5 0.5v2c0 0.276 0.224 0.5 0.5 0.5zM11.5 3c0.276 0 0.5-0.224 0.5-0.5v-2c0-0.276-0.224-0.5-0.5-0.5s-0.5 0.224-0.5 0.5v2c0 0.276 0.224 0.5 0.5 0.5zM9 6h-5v1h4v2h-4v1h4v2h-4v1h5zM11 13h1v-7h-2v1h1zM13.625 15.375h-11.25c-0.55 0-1-0.325-1-0.875v0.5c0 0.55 0.45 1 1 1h11.25c0.55 0 1-0.45 1-1v-0.5c0 0.55-0.45 0.875-1 0.875z"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 868 B |
|
@ -0,0 +1,5 @@
|
|||
<!-- Generated by IcoMoon.io -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<title>envelop</title>
|
||||
<path d="M15 2h-14c-0.55 0-1 0.45-1 1v10c0 0.55 0.45 1 1 1h14c0.55 0 1-0.45 1-1v-10c0-0.55-0.45-1-1-1zM5.831 9.773l-3 2.182c-0.1 0.073-0.216 0.108-0.33 0.108-0.174 0-0.345-0.080-0.455-0.232-0.183-0.251-0.127-0.603 0.124-0.786l3-2.182c0.251-0.183 0.603-0.127 0.786 0.124s0.127 0.603-0.124 0.786zM13.955 11.831c-0.11 0.151-0.282 0.232-0.455 0.232-0.115 0-0.23-0.035-0.33-0.108l-3-2.182c-0.251-0.183-0.307-0.534-0.124-0.786s0.535-0.307 0.786-0.124l3 2.182c0.251 0.183 0.307 0.535 0.124 0.786zM13.831 4.955l-5.5 4c-0.099 0.072-0.215 0.108-0.331 0.108s-0.232-0.036-0.331-0.108l-5.5-4c-0.251-0.183-0.307-0.534-0.124-0.786s0.535-0.307 0.786-0.124l5.169 3.759 5.169-3.759c0.251-0.183 0.603-0.127 0.786 0.124s0.127 0.603-0.124 0.786z"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 895 B |
|
@ -0,0 +1,8 @@
|
|||
<!-- Generated by IcoMoon.io -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<title>envelop2</title>
|
||||
<path d="M14.998 3c0.001 0.001 0.001 0.001 0.002 0.002v9.996c-0.001 0.001-0.001 0.001-0.002 0.002h-13.996c-0.001-0.001-0.001-0.001-0.002-0.002v-9.996c0.001-0.001 0.001-0.001 0.002-0.002h13.996zM15 2h-14c-0.55 0-1 0.45-1 1v10c0 0.55 0.45 1 1 1h14c0.55 0 1-0.45 1-1v-10c0-0.55-0.45-1-1-1v0z"></path>
|
||||
<path d="M5.831 9.773l-3 2.182c-0.1 0.073-0.216 0.108-0.33 0.108-0.174 0-0.345-0.080-0.455-0.232-0.183-0.251-0.127-0.603 0.124-0.786l3-2.182c0.251-0.183 0.603-0.127 0.786 0.124s0.127 0.603-0.124 0.786z"></path>
|
||||
<path d="M13.955 11.831c-0.11 0.151-0.282 0.232-0.455 0.232-0.115 0-0.23-0.035-0.33-0.108l-3-2.182c-0.251-0.183-0.307-0.534-0.124-0.786s0.534-0.307 0.786-0.124l3 2.182c0.251 0.183 0.307 0.535 0.124 0.786z"></path>
|
||||
<path d="M13.831 4.955l-5.5 4c-0.099 0.072-0.215 0.108-0.331 0.108s-0.232-0.036-0.331-0.108l-5.5-4c-0.251-0.183-0.307-0.534-0.124-0.786s0.535-0.307 0.786-0.124l5.169 3.759 5.169-3.759c0.251-0.183 0.603-0.127 0.786 0.124s0.127 0.603-0.124 0.786v0z"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
|
@ -0,0 +1,5 @@
|
|||
<!-- Generated by IcoMoon.io -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<title>envelop3</title>
|
||||
<path d="M15 2h-14c-0.55 0-1 0.45-1 1v10c0 0.55 0.45 1 1 1h14c0.55 0 1-0.45 1-1v-10c0-0.55-0.45-1-1-1zM14 4v0.719l-6 3.536-6-3.536v-0.719h12zM2 12v-5.54l6 3.536 6-3.536v5.54h-12z"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 350 B |
|
@ -0,0 +1,5 @@
|
|||
<!-- Generated by IcoMoon.io -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<title>envelop4</title>
|
||||
<path d="M14.5 2h-13c-0.825 0-1.5 0.675-1.5 1.5v10c0 0.825 0.675 1.5 1.5 1.5h13c0.825 0 1.5-0.675 1.5-1.5v-10c0-0.825-0.675-1.5-1.5-1.5zM6.23 8.6l-4.23 3.295v-7.838l4.23 4.543zM2.756 4h10.488l-5.244 3.938-5.244-3.938zM6.395 8.777l1.605 1.723 1.605-1.723 3.29 4.223h-9.79l3.29-4.223zM9.77 8.6l4.23-4.543v7.838l-4.23-3.295z"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 493 B |
|
@ -0,0 +1,5 @@
|
|||
<!-- Generated by IcoMoon.io -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<title>envelop5</title>
|
||||
<path d="M14.5 2h-13c-0.825 0-1.5 0.675-1.5 1.5v9c0 0.825 0.675 1.5 1.5 1.5h13c0.825 0 1.5-0.675 1.5-1.5v-9c0-0.825-0.675-1.5-1.5-1.5zM14 5l-6 4.5-6-4.5v-1l6 3 6-3v1z"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 338 B |
|
@ -0,0 +1,7 @@
|
|||
<!-- Generated by IcoMoon.io -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<title>watch</title>
|
||||
<path d="M11 3h-0.5l-0.5-3h-5l-0.5 3h-0.5c-1.1 0-2 0.75-2 1.667v6.667c0 0.917 0.9 1.667 2 1.667h0.5l0.5 3h5l0.5-3h0.5c1.1 0 2-0.75 2-1.667v-6.667c0-0.917-0.9-1.667-2-1.667zM12 11.333c0 0.191-0.143 0.338-0.228 0.409-0.197 0.164-0.478 0.258-0.772 0.258h-7c-0.294 0-0.576-0.094-0.772-0.258-0.085-0.071-0.228-0.218-0.228-0.409v-6.667c0-0.191 0.143-0.338 0.228-0.409 0.197-0.164 0.478-0.258 0.772-0.258h7c0.294 0 0.576 0.094 0.772 0.258 0.085 0.071 0.228 0.218 0.228 0.409v6.667z"></path>
|
||||
<path d="M6.5 6h-2c-0.276 0-0.5 0.224-0.5 0.5s0.224 0.5 0.5 0.5h1.5v1h-1.5c-0.276 0-0.5 0.224-0.5 0.5v2c0 0.276 0.224 0.5 0.5 0.5h2c0.276 0 0.5-0.224 0.5-0.5s-0.224-0.5-0.5-0.5h-1.5v-1h1.5c0.276 0 0.5-0.224 0.5-0.5v-2c0-0.276-0.224-0.5-0.5-0.5z"></path>
|
||||
<path d="M10.5 6c-0.276 0-0.5 0.224-0.5 0.5v1.5h-1v-1.5c0-0.276-0.224-0.5-0.5-0.5s-0.5 0.224-0.5 0.5v2c0 0.276 0.224 0.5 0.5 0.5h1.5v1.5c0 0.276 0.224 0.5 0.5 0.5s0.5-0.224 0.5-0.5v-4c0-0.276-0.224-0.5-0.5-0.5z"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
|
@ -424,6 +424,94 @@ function initActorActions(store, router) {
|
|||
};
|
||||
}
|
||||
|
||||
async function searchActors({ _commit }, { query, limit = 20, minLength = 2 }) {
|
||||
const { actors } = await graphql(`
|
||||
query SearchActors(
|
||||
$query: String!
|
||||
$limit: Int = 20
|
||||
$minLength: Int = 2
|
||||
$hasAuth: Boolean!
|
||||
$userId: Int
|
||||
) {
|
||||
actors: searchActors(
|
||||
search: $query,
|
||||
minLength: $minLength
|
||||
first: $limit
|
||||
) {
|
||||
id
|
||||
name
|
||||
slug
|
||||
age
|
||||
ageAtDeath
|
||||
dateOfBirth
|
||||
dateOfDeath
|
||||
gender
|
||||
aliasFor: actorByAliasFor {
|
||||
id
|
||||
name
|
||||
slug
|
||||
age
|
||||
ageAtDeath
|
||||
dateOfBirth
|
||||
dateOfDeath
|
||||
gender
|
||||
entity {
|
||||
id
|
||||
name
|
||||
slug
|
||||
}
|
||||
avatar: avatarMedia {
|
||||
id
|
||||
path
|
||||
thumbnail
|
||||
lazy
|
||||
isS3
|
||||
width
|
||||
height
|
||||
comment
|
||||
credit
|
||||
}
|
||||
birthCountry: countryByBirthCountryAlpha2 {
|
||||
alpha2
|
||||
name
|
||||
alias
|
||||
}
|
||||
}
|
||||
entity {
|
||||
id
|
||||
name
|
||||
slug
|
||||
}
|
||||
avatar: avatarMedia {
|
||||
id
|
||||
path
|
||||
thumbnail
|
||||
lazy
|
||||
isS3
|
||||
width
|
||||
height
|
||||
comment
|
||||
credit
|
||||
}
|
||||
birthCountry: countryByBirthCountryAlpha2 {
|
||||
alpha2
|
||||
name
|
||||
alias
|
||||
}
|
||||
${actorStashesFields}
|
||||
}
|
||||
}
|
||||
`, {
|
||||
query,
|
||||
limit,
|
||||
minLength,
|
||||
hasAuth: !!store.state.auth.user,
|
||||
userId: store.state.auth.user?.id,
|
||||
});
|
||||
|
||||
return actors.map(actor => curateActor(actor));
|
||||
}
|
||||
|
||||
async function fetchActorReleases({ _commit }, actorId) {
|
||||
const releases = await get(`/actors/${actorId}/releases`, {
|
||||
filter: store.state.ui.filter,
|
||||
|
@ -438,6 +526,7 @@ function initActorActions(store, router) {
|
|||
fetchActorById,
|
||||
fetchActors,
|
||||
fetchActorReleases,
|
||||
searchActors,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -152,6 +152,32 @@ function curateStash(stash) {
|
|||
return curatedStash;
|
||||
}
|
||||
|
||||
function curateAlert(alert) {
|
||||
if (!alert) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const curatedAlert = alert;
|
||||
|
||||
if (alert.actors) {
|
||||
curatedAlert.actors = alert.actors.map(actor => curateActor(actor.actor || actor));
|
||||
}
|
||||
|
||||
if (alert.tags) {
|
||||
curatedAlert.tags = alert.tags.map(tag => curateTag(tag.tag || tag));
|
||||
}
|
||||
|
||||
if (alert.entity) {
|
||||
curatedAlert.entity = curateEntity(alert.entity.entity || alert.entity);
|
||||
}
|
||||
|
||||
if (alert.stashes) {
|
||||
curatedAlert.stashes = alert.stashes.map(stash => curateStash(stash.stash || stash));
|
||||
}
|
||||
|
||||
return curatedAlert;
|
||||
}
|
||||
|
||||
function curateUser(user) {
|
||||
if (!user) {
|
||||
return null;
|
||||
|
@ -163,6 +189,10 @@ function curateUser(user) {
|
|||
curatedUser.stashes = user.stashes.map(stash => curateStash(stash.stash || stash));
|
||||
}
|
||||
|
||||
if (user.alerts) {
|
||||
curatedUser.alerts = user.alerts.map(alert => curateAlert(alert.alert || alert));
|
||||
}
|
||||
|
||||
return curatedUser;
|
||||
}
|
||||
|
||||
|
|
|
@ -250,6 +250,7 @@ function initEntitiesActions(store, router) {
|
|||
search: $query,
|
||||
first: $limit
|
||||
) {
|
||||
id
|
||||
name
|
||||
slug
|
||||
type
|
||||
|
|
|
@ -280,9 +280,10 @@ const releasesFragment = `
|
|||
releasesTagsConnection: {
|
||||
none: {
|
||||
tag: {
|
||||
slug: {
|
||||
in: $exclude
|
||||
}
|
||||
or: [
|
||||
{ slug: { in: $exclude } }
|
||||
{ name: { in: $exclude } }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -477,6 +478,7 @@ function getIncludedActors(router) {
|
|||
}
|
||||
|
||||
export {
|
||||
actorFields,
|
||||
actorStashesFields,
|
||||
releaseActorsFragment,
|
||||
releaseFields,
|
||||
|
|
|
@ -211,6 +211,72 @@ function initTagsActions(store, _router) {
|
|||
return tags.map(tag => curateTag(tag, store.state.ui.sfw));
|
||||
}
|
||||
|
||||
async function searchTags({ _commit }, {
|
||||
limit = 100,
|
||||
minLength = 2,
|
||||
query,
|
||||
_group,
|
||||
_priority,
|
||||
}) {
|
||||
const { tags } = await graphql(`
|
||||
query SearchTags(
|
||||
$query: String!,
|
||||
$limit: Int = 100
|
||||
$minLength: Int = 2
|
||||
) {
|
||||
tags: searchTags(
|
||||
search: $query,
|
||||
first: $limit
|
||||
minLength: $minLength
|
||||
) {
|
||||
id
|
||||
name
|
||||
slug
|
||||
poster: tagsPosterByTagId {
|
||||
media {
|
||||
thumbnail
|
||||
comment
|
||||
lazy
|
||||
width
|
||||
height
|
||||
thumbnailWidth
|
||||
thumbnailHeight
|
||||
entity {
|
||||
id
|
||||
name
|
||||
slug
|
||||
type
|
||||
independent
|
||||
parent {
|
||||
id
|
||||
name
|
||||
slug
|
||||
type
|
||||
independent
|
||||
}
|
||||
}
|
||||
sfw: sfwMedia {
|
||||
thumbnail
|
||||
comment
|
||||
lazy
|
||||
}
|
||||
}
|
||||
}
|
||||
group {
|
||||
name
|
||||
slug
|
||||
}
|
||||
}
|
||||
}
|
||||
`, {
|
||||
query,
|
||||
limit,
|
||||
minLength,
|
||||
});
|
||||
|
||||
return tags.map(tag => curateTag(tag, store.state.ui.sfw));
|
||||
}
|
||||
|
||||
async function fetchTagReleases({ _commit }, tagId) {
|
||||
const releases = await get(`/tags/${tagId}/releases`, {
|
||||
filter: store.state.ui.filter,
|
||||
|
@ -225,6 +291,7 @@ function initTagsActions(store, _router) {
|
|||
fetchTagBySlug,
|
||||
fetchTags,
|
||||
fetchTagReleases,
|
||||
searchTags,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { graphql } from '../api';
|
||||
import { releaseFields } from '../fragments';
|
||||
import { graphql, post, del } from '../api';
|
||||
import { actorFields, releaseFields } from '../fragments';
|
||||
import { curateUser } from '../curate';
|
||||
|
||||
function initUsersActions(store, _router) {
|
||||
|
@ -55,6 +55,48 @@ function initUsersActions(store, _router) {
|
|||
}
|
||||
}
|
||||
}
|
||||
alerts {
|
||||
id
|
||||
notify
|
||||
email
|
||||
stashes: alertsStashes {
|
||||
stash {
|
||||
id
|
||||
name
|
||||
slug
|
||||
}
|
||||
}
|
||||
tags: alertsTags {
|
||||
tag {
|
||||
id
|
||||
name
|
||||
slug
|
||||
}
|
||||
}
|
||||
actors: alertsActors {
|
||||
actor {
|
||||
${actorFields}
|
||||
}
|
||||
}
|
||||
entity: alertsEntityByAlertId {
|
||||
entity {
|
||||
id
|
||||
name
|
||||
slug
|
||||
type
|
||||
independent
|
||||
hasLogo
|
||||
parent {
|
||||
id
|
||||
name
|
||||
slug
|
||||
type
|
||||
independent
|
||||
hasLogo
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`, {
|
||||
|
@ -66,8 +108,18 @@ function initUsersActions(store, _router) {
|
|||
return curateUser(user);
|
||||
}
|
||||
|
||||
async function addAlert(context, alert) {
|
||||
return post('/alerts', alert);
|
||||
}
|
||||
|
||||
async function removeAlert(context, alertId) {
|
||||
return del(`/alerts/${alertId}`);
|
||||
}
|
||||
|
||||
return {
|
||||
addAlert,
|
||||
fetchUser,
|
||||
removeAlert,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1138,6 +1138,109 @@ exports.up = knex => Promise.resolve()
|
|||
.notNullable()
|
||||
.defaultTo(knex.fn.now());
|
||||
}))
|
||||
.then(() => knex.schema.createTable('alerts', (table) => {
|
||||
table.increments('id');
|
||||
|
||||
table.integer('user_id')
|
||||
.notNullable()
|
||||
.references('id')
|
||||
.inTable('users')
|
||||
.onDelete('cascade');
|
||||
|
||||
table.boolean('notify')
|
||||
.defaultTo(false);
|
||||
|
||||
table.boolean('email')
|
||||
.defaultTo(false);
|
||||
|
||||
table.datetime('created_at')
|
||||
.notNullable()
|
||||
.defaultTo(knex.fn.now());
|
||||
}))
|
||||
.then(() => knex.schema.createTable('alerts_scenes', (table) => {
|
||||
table.increments('id');
|
||||
|
||||
table.integer('alert_id')
|
||||
.notNullable()
|
||||
.references('id')
|
||||
.inTable('alerts')
|
||||
.onDelete('cascade');
|
||||
|
||||
table.integer('scene_id')
|
||||
.notNullable()
|
||||
.references('id')
|
||||
.inTable('releases')
|
||||
.onDelete('cascade');
|
||||
|
||||
table.unique(['alert_id', 'scene_id']);
|
||||
}))
|
||||
.then(() => knex.schema.createTable('alerts_actors', (table) => {
|
||||
table.increments('id');
|
||||
|
||||
table.integer('alert_id')
|
||||
.notNullable()
|
||||
.references('id')
|
||||
.inTable('alerts')
|
||||
.onDelete('cascade');
|
||||
|
||||
table.integer('actor_id')
|
||||
.notNullable()
|
||||
.references('id')
|
||||
.inTable('actors')
|
||||
.onDelete('cascade');
|
||||
|
||||
table.unique(['alert_id', 'actor_id']);
|
||||
}))
|
||||
.then(() => knex.schema.createTable('alerts_tags', (table) => {
|
||||
table.increments('id');
|
||||
|
||||
table.integer('alert_id')
|
||||
.notNullable()
|
||||
.references('id')
|
||||
.inTable('alerts')
|
||||
.onDelete('cascade');
|
||||
|
||||
table.integer('tag_id')
|
||||
.notNullable()
|
||||
.references('id')
|
||||
.inTable('tags')
|
||||
.onDelete('cascade');
|
||||
|
||||
table.unique(['alert_id', 'tag_id']);
|
||||
}))
|
||||
.then(() => knex.schema.createTable('alerts_entities', (table) => {
|
||||
table.increments('id');
|
||||
|
||||
table.integer('alert_id')
|
||||
.notNullable()
|
||||
.unique()
|
||||
.references('id')
|
||||
.inTable('alerts')
|
||||
.onDelete('cascade');
|
||||
|
||||
table.integer('entity_id')
|
||||
.notNullable()
|
||||
.references('id')
|
||||
.inTable('entities')
|
||||
.onDelete('cascade');
|
||||
}))
|
||||
.then(() => knex.schema.createTable('alerts_stashes', (table) => {
|
||||
table.increments('id');
|
||||
|
||||
table.integer('alert_id')
|
||||
.notNullable()
|
||||
.references('id')
|
||||
.inTable('alerts')
|
||||
.onDelete('cascade');
|
||||
|
||||
table.integer('stash_id')
|
||||
.notNullable()
|
||||
.references('id')
|
||||
.inTable('stashes')
|
||||
.onDelete('cascade');
|
||||
|
||||
table.unique(['alert_id', 'stash_id']);
|
||||
}))
|
||||
// SEARCH
|
||||
.then(() => { // eslint-disable-line arrow-body-style
|
||||
// allow vim fold
|
||||
|
@ -1192,12 +1295,23 @@ exports.up = knex => Promise.resolve()
|
|||
url ILIKE ('%' || search || '%')
|
||||
$$ LANGUAGE SQL STABLE;
|
||||
|
||||
CREATE FUNCTION search_actors(search text, min_length numeric DEFAULT 2) RETURNS SETOF actors AS $$
|
||||
CREATE FUNCTION search_actors(search text, min_length smallint DEFAULT 2) RETURNS SETOF actors AS $$
|
||||
SELECT * FROM actors
|
||||
WHERE length(search) >= min_length
|
||||
AND name ILIKE ('%' || TRIM(search) || '%')
|
||||
$$ LANGUAGE SQL STABLE;
|
||||
|
||||
CREATE FUNCTION search_tags(search text, min_length smallint DEFAULT 2, is_primary boolean DEFAULT true) RETURNS SETOF tags AS $$
|
||||
SELECT * FROM tags
|
||||
WHERE length(search) >= min_length
|
||||
AND name ILIKE ('%' || TRIM(search) || '%')
|
||||
AND CASE
|
||||
WHEN is_primary
|
||||
THEN tags.alias_for IS NULL
|
||||
ELSE true
|
||||
END
|
||||
$$ LANGUAGE SQL STABLE;
|
||||
|
||||
CREATE FUNCTION actors_tags(actor actors, selectable_tags text[]) RETURNS SETOF tags AS $$
|
||||
SELECT tags.*
|
||||
FROM releases_actors
|
||||
|
@ -1374,6 +1488,58 @@ exports.up = knex => Promise.resolve()
|
|||
WHERE stashes.id = stashes_actors.stash_id
|
||||
AND (stashes.user_id = current_user_id() OR stashes.public)
|
||||
));
|
||||
|
||||
ALTER TABLE alerts ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE alerts_tags ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE alerts_scenes ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE alerts_actors ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE alerts_entities ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE alerts_stashes ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
CREATE POLICY alerts_policy_select ON alerts FOR SELECT USING (alerts.user_id = current_user_id());
|
||||
CREATE POLICY alerts_policy_update ON alerts FOR UPDATE USING (alerts.user_id = current_user_id());
|
||||
CREATE POLICY alerts_policy_delete ON alerts FOR DELETE USING (alerts.user_id = current_user_id());
|
||||
CREATE POLICY alerts_policy_insert ON alerts FOR INSERT WITH CHECK (true);
|
||||
|
||||
CREATE POLICY alerts_policy ON alerts_scenes
|
||||
USING (EXISTS (
|
||||
SELECT *
|
||||
FROM alerts
|
||||
WHERE alerts.id = alerts_scenes.alert_id
|
||||
AND alerts.user_id = current_user_id()
|
||||
));
|
||||
|
||||
CREATE POLICY alerts_policy ON alerts_actors
|
||||
USING (EXISTS (
|
||||
SELECT *
|
||||
FROM alerts
|
||||
WHERE alerts.id = alerts_actors.alert_id
|
||||
AND alerts.user_id = current_user_id()
|
||||
));
|
||||
|
||||
CREATE POLICY alerts_policy ON alerts_entities
|
||||
USING (EXISTS (
|
||||
SELECT *
|
||||
FROM alerts
|
||||
WHERE alerts.id = alerts_entities.alert_id
|
||||
AND alerts.user_id = current_user_id()
|
||||
));
|
||||
|
||||
CREATE POLICY alerts_policy ON alerts_tags
|
||||
USING (EXISTS (
|
||||
SELECT *
|
||||
FROM alerts
|
||||
WHERE alerts.id = alerts_tags.alert_id
|
||||
AND alerts.user_id = current_user_id()
|
||||
));
|
||||
|
||||
CREATE POLICY alerts_policy ON alerts_stashes
|
||||
USING (EXISTS (
|
||||
SELECT *
|
||||
FROM alerts
|
||||
WHERE alerts.id = alerts_stashes.alert_id
|
||||
AND alerts.user_id = current_user_id()
|
||||
));
|
||||
`, {
|
||||
visitor: knex.raw(config.database.query.user),
|
||||
});
|
||||
|
@ -1398,6 +1564,8 @@ exports.up = knex => Promise.resolve()
|
|||
COMMENT ON FUNCTION actors_scenes IS E'@sortable';
|
||||
COMMENT ON FUNCTION tags_scenes IS E'@sortable';
|
||||
COMMENT ON FUNCTION search_releases IS E'@sortable';
|
||||
COMMENT ON FUNCTION search_actors IS E'@sortable';
|
||||
COMMENT ON FUNCTION search_tags IS E'@sortable';
|
||||
`);
|
||||
});
|
||||
|
||||
|
@ -1468,6 +1636,13 @@ exports.down = (knex) => { // eslint-disable-line arrow-body-style
|
|||
DROP TABLE IF EXISTS stashes_actors CASCADE;
|
||||
DROP TABLE IF EXISTS stashes CASCADE;
|
||||
|
||||
DROP TABLE IF EXISTS alerts_scenes CASCADE;
|
||||
DROP TABLE IF EXISTS alerts_actors CASCADE;
|
||||
DROP TABLE IF EXISTS alerts_tags CASCADE;
|
||||
DROP TABLE IF EXISTS alerts_entities CASCADE;
|
||||
DROP TABLE IF EXISTS alerts_stashes CASCADE;
|
||||
DROP TABLE IF EXISTS alerts CASCADE;
|
||||
|
||||
DROP TABLE IF EXISTS users CASCADE;
|
||||
DROP TABLE IF EXISTS users_roles CASCADE;
|
||||
|
||||
|
@ -1475,6 +1650,7 @@ exports.down = (knex) => { // eslint-disable-line arrow-body-style
|
|||
DROP FUNCTION IF EXISTS search_sites;
|
||||
DROP FUNCTION IF EXISTS search_entities;
|
||||
DROP FUNCTION IF EXISTS search_actors;
|
||||
DROP FUNCTION IF EXISTS search_tags;
|
||||
DROP FUNCTION IF EXISTS get_random_sfw_media_id;
|
||||
|
||||
DROP FUNCTION IF EXISTS releases_is_new;
|
||||
|
|
After Width: | Height: | Size: 31 KiB |
After Width: | Height: | Size: 51 KiB |
After Width: | Height: | Size: 30 KiB |
|
@ -4554,7 +4554,7 @@ const sites = [
|
|||
{
|
||||
slug: 'legalporno',
|
||||
name: 'LegalPorno',
|
||||
alias: ['clip'],
|
||||
alias: ['clip', 'analvids', 'gonzo'],
|
||||
url: 'https://www.legalporno.com',
|
||||
description: 'The Best HD Porn For You!',
|
||||
independent: true,
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
'use strict';
|
||||
|
||||
const knex = require('./knex');
|
||||
const { HttpError } = require('./errors');
|
||||
|
||||
async function addAlert(alert, sessionUser) {
|
||||
if (!sessionUser) {
|
||||
throw new HttpError('You are not authenthicated', 401);
|
||||
}
|
||||
|
||||
if (!alert.actors?.length > 0 && !alert.tags?.length > 0 && !alert.entity) {
|
||||
throw new HttpError('Alert must contain at least one actor, tag or entity', 400);
|
||||
}
|
||||
|
||||
const [alertId] = await knex('alerts')
|
||||
.insert({
|
||||
user_id: sessionUser.id,
|
||||
notify: alert.notify,
|
||||
email: alert.email,
|
||||
})
|
||||
.returning('id');
|
||||
|
||||
await Promise.all([
|
||||
alert.actors?.length > 0 && knex('alerts_actors')
|
||||
.insert(alert.actors.map(actorId => ({
|
||||
alert_id: alertId,
|
||||
actor_id: actorId,
|
||||
}))),
|
||||
alert.tags?.length > 0 && knex('alerts_tags')
|
||||
.insert(alert.tags.map(tagId => ({
|
||||
alert_id: alertId,
|
||||
tag_id: tagId,
|
||||
}))),
|
||||
alert.stashes?.length > 0 && knex('alerts_stashes')
|
||||
.insert(alert.stashes.map(stashId => ({
|
||||
alert_id: alertId,
|
||||
stash_id: stashId,
|
||||
}))),
|
||||
alert.entity && knex('alerts_entities').insert({
|
||||
alert_id: alertId,
|
||||
entity_id: alert.entity,
|
||||
}),
|
||||
]);
|
||||
|
||||
return alertId;
|
||||
}
|
||||
|
||||
async function removeAlert(alertId) {
|
||||
await knex('alerts').where('id', alertId).delete();
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
addAlert,
|
||||
removeAlert,
|
||||
};
|
|
@ -358,6 +358,7 @@ async function writeThumbnail(image, thumbpath) {
|
|||
withoutEnlargement: true,
|
||||
})
|
||||
.jpeg({ quality: config.media.thumbnailQuality })
|
||||
.rotate()
|
||||
.toFile(path.join(config.media.path, thumbpath));
|
||||
}
|
||||
|
||||
|
@ -368,6 +369,7 @@ async function writeLazy(image, lazypath) {
|
|||
withoutEnlargement: true,
|
||||
})
|
||||
.jpeg({ quality: config.media.lazyQuality })
|
||||
.rotate()
|
||||
.toFile(path.join(config.media.path, lazypath));
|
||||
}
|
||||
|
||||
|
@ -444,8 +446,9 @@ async function storeImageFile(media, hashDir, hashSubDir, filename, filedir, fil
|
|||
},
|
||||
meta: {
|
||||
...media.meta,
|
||||
width: info.width,
|
||||
height: info.height,
|
||||
// 6 or 8 implies image is sideways, and size is not inherently adjusted for orientation
|
||||
width: info.orientation === 6 || info.orientation === 8 ? info.height : info.width,
|
||||
height: info.orientation === 6 || info.orientation === 8 ? info.width : info.height,
|
||||
entropy: stats?.entropy || null,
|
||||
sharpness: stats?.sharpness || null,
|
||||
},
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
'use strict';
|
||||
|
||||
const { addAlert, removeAlert } = require('../alerts');
|
||||
|
||||
async function addAlertApi(req, res) {
|
||||
const alertId = await addAlert(req.body, req.session.user);
|
||||
|
||||
res.send({ id: alertId });
|
||||
}
|
||||
|
||||
async function removeAlertApi(req, res) {
|
||||
await removeAlert(req.params.alertId);
|
||||
|
||||
res.status(204).send();
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
addAlert: addAlertApi,
|
||||
removeAlert: removeAlertApi,
|
||||
};
|
|
@ -55,6 +55,11 @@ const {
|
|||
updateStash,
|
||||
} = require('./stashes');
|
||||
|
||||
const {
|
||||
addAlert,
|
||||
removeAlert,
|
||||
} = require('./alerts');
|
||||
|
||||
async function initServer() {
|
||||
const app = express();
|
||||
const router = Router();
|
||||
|
@ -98,6 +103,9 @@ async function initServer() {
|
|||
router.delete('/api/stashes/:stashId/scenes/:sceneId', unstashScene);
|
||||
router.delete('/api/stashes/:stashId/movies/:movieId', unstashMovie);
|
||||
|
||||
router.post('/api/alerts', addAlert);
|
||||
router.delete('/api/alerts/:alertId', removeAlert);
|
||||
|
||||
router.get('/api/scenes', fetchScenes);
|
||||
router.get('/api/scenes/:releaseId', fetchScene);
|
||||
router.get('/api/scenes/:releaseId/poster', fetchScenePoster);
|
||||
|
|