Generalized filters bar, added to network page.

This commit is contained in:
ThePendulum 2019-11-15 02:37:17 +01:00
parent 23492bb5d0
commit 0575dbc7e4
17 changed files with 193 additions and 113 deletions

View File

@ -7,7 +7,7 @@
:checked="range === 'all'"
type="radio"
class="range-input"
@click="$emit('set-range', 'all')"
@click="setRange('all')"
>
<label
:for="`${_uid}-all`"
@ -21,7 +21,7 @@
:checked="range === 'new'"
type="radio"
class="range-input"
@click="$emit('set-range', 'new')"
@click="setRange('new')"
>
<label
:for="`${_uid}-new`"
@ -35,7 +35,7 @@
:checked="range === 'upcoming'"
type="radio"
class="range-input"
@click="$emit('set-range', 'upcoming')"
@click="setRange('upcoming')"
>
<label
:for="`${_uid}-upcoming`"
@ -50,7 +50,7 @@
<Filters
class="filters-container"
:filter="filter"
@set-filter="filter => $emit('set-filter', filter)"
@set-filter="setFilter"
/>
<v-popover class="filters-compact">
@ -60,7 +60,7 @@
<Filters
:compact="true"
:filter="filter"
@set-filter="filter => $emit('set-filter', filter)"
@set-filter="setFilter"
/>
</div>
</v-popover>
@ -69,22 +69,49 @@
</template>
<script>
import { mapState } from 'vuex';
import Filters from './filters.vue';
function filter(state) {
return state.ui.filter;
}
function range(state) {
return state.ui.range;
}
async function setFilter(newFilter) {
this.$store.dispatch('setFilter', newFilter);
await this.fetchReleases();
}
async function setRange(newRange) {
this.$store.dispatch('setRange', newRange);
await this.fetchReleases();
}
export default {
components: {
Filters,
},
props: {
filter: {
type: Array,
default: () => [],
},
range: {
type: String,
fetchReleases: {
type: Function,
default: null,
},
},
computed: {
...mapState({
filter,
range,
}),
},
methods: {
setFilter,
setRange,
},
};
</script>

View File

@ -1,11 +1,6 @@
<template>
<div class="content">
<FilterBar
:filter="filter"
:range="range"
@set-filter="setFilter"
@set-range="setRange"
/>
<FilterBar :fetch-releases="fetchReleases" />
<div class="content-inner">
<ul class="scenes nolist">
@ -22,30 +17,11 @@
</template>
<script>
import FilterBar from './filter-bar.vue';
import FilterBar from '../header/filter-bar.vue';
import ReleaseTile from '../tile/release.vue';
import rangeDates from '../../js/range-dates';
async function fetchReleases() {
this.releases = await this.$store.dispatch('fetchReleases', {
filter: this.filter,
...rangeDates(this.range),
});
}
async function setFilter(filter) {
this.filter = filter;
localStorage.setItem('filter', this.filter);
await this.fetchReleases();
}
async function setRange(range) {
this.range = range;
localStorage.setItem('range', this.range);
await this.fetchReleases();
this.releases = await this.$store.dispatch('fetchReleases');
}
async function mounted() {
@ -60,12 +36,7 @@ export default {
ReleaseTile,
},
data() {
const storedFilter = localStorage.getItem('filter');
const storedRange = localStorage.getItem('range');
return {
filter: storedFilter ? storedFilter.split(',') : ['gay', 'transsexual'],
range: storedRange || 'new',
releases: [],
networks: [],
pageTitle: null,
@ -74,8 +45,6 @@ export default {
mounted,
methods: {
fetchReleases,
setFilter,
setRange,
},
};
</script>

View File

@ -3,6 +3,8 @@
v-if="network"
class="content network"
>
<FilterBar :fetch-releases="fetchReleases" />
<div class="content-inner">
<div class="header">
<a
@ -54,12 +56,19 @@
</template>
<script>
import FilterBar from '../header/filter-bar.vue';
import ReleaseTile from '../tile/release.vue';
import SiteTile from '../tile/site.vue';
async function mounted() {
[this.network] = await this.$store.dispatch('fetchNetworks', this.$route.params.networkSlug);
async function fetchReleases() {
this.releases = await this.$store.dispatch('fetchNetworkReleases', this.$route.params.networkSlug);
}
async function mounted() {
[[this.network]] = await Promise.all([
this.$store.dispatch('fetchNetworks', this.$route.params.networkSlug),
this.fetchReleases(),
]);
this.sites = this.network.sites
.filter(site => !site.independent)
@ -70,6 +79,7 @@ async function mounted() {
export default {
components: {
FilterBar,
ReleaseTile,
SiteTile,
},
@ -82,6 +92,9 @@ export default {
};
},
mounted,
methods: {
fetchReleases,
},
};
</script>

View File

@ -207,7 +207,7 @@ function pageTitle() {
}
async function mounted() {
this.release = await this.$store.dispatch('fetchReleases', { id: this.$route.params.releaseId });
this.release = await this.$store.dispatch('fetchReleaseById', this.$route.params.releaseId);
}
export default {

View File

@ -1,14 +1,20 @@
import { get } from '../api';
function initNetworksActions(_store, _router) {
function initNetworksActions(store, _router) {
async function fetchNetworks({ _commit }, networkId) {
const networks = await get(`/networks/${networkId || ''}`);
const networks = await get(`/networks/${networkId || ''}`, {
});
return networks;
}
async function fetchNetworkReleases({ _commit }, networkId) {
const releases = await get(`/networks/${networkId}/releases`);
const releases = await get(`/networks/${networkId}/releases`, {
filter: store.state.ui.filter,
after: store.getters.after,
before: store.getters.before,
});
return releases;
}

View File

@ -1,18 +0,0 @@
function rangeDates(range) {
return ({
new: () => ({
after: new Date(0),
before: new Date(),
}),
upcoming: () => ({
after: new Date(),
before: new Date(2 ** 42),
}),
all: () => ({
after: new Date(0),
before: new Date(2 ** 42),
}),
})[range]();
}
export default rangeDates;

View File

@ -1,28 +1,25 @@
import dayjs from 'dayjs';
import { get } from '../api';
function initReleasesActions(_store, _router) {
async function fetchReleases({ _commit }, {
id,
filter,
after,
before,
}) {
const afterString = dayjs(after).format('YYYY-MM-DD');
const beforeString = dayjs(before).format('YYYY-MM-DD');
const releases = await get(`/releases/${id || ''}`, {
filter,
after: afterString,
before: beforeString,
function initReleasesActions(store, _router) {
async function fetchReleases({ _commit }) {
const releases = await get('/releases', {
filter: store.state.ui.filter,
after: store.getters.after,
before: store.getters.before,
});
return releases;
}
async function fetchReleaseById({ _commit }, releaseId) {
const release = await get(`/releases/${releaseId}`);
return release;
}
return {
fetchReleases,
fetchReleaseById,
};
}

View File

@ -1,6 +1,7 @@
import Vue from 'vue';
import Vuex from 'vuex';
import initUiStore from './ui/ui';
import initAuthStore from './auth/auth';
import initReleasesStore from './releases/releases';
import initSitesStore from './sites/sites';
@ -13,6 +14,7 @@ function initStore(router) {
const store = new Vuex.Store();
store.registerModule('ui', initUiStore(store, router));
store.registerModule('auth', initAuthStore(store, router));
store.registerModule('releases', initReleasesStore(store, router));
store.registerModule('actors', initActorsStore(store, router));

20
assets/js/ui/actions.js Normal file
View File

@ -0,0 +1,20 @@
// import { get } from '../api';
function initUiActions(_store, _router) {
function setFilter({ commit }, filter) {
commit('setFilter', filter);
localStorage.setItem('filter', filter);
}
function setRange({ commit }, range) {
commit('setRange', range);
localStorage.setItem('range', range);
}
return {
setFilter,
setRange,
};
}
export default initUiActions;

34
assets/js/ui/getters.js Normal file
View File

@ -0,0 +1,34 @@
import dayjs from 'dayjs';
const dateRanges = {
new: () => ({
after: dayjs(new Date(0)).format('YYYY-MM-DD'),
before: dayjs(new Date()).format('YYYY-MM-DD'),
}),
upcoming: () => ({
after: dayjs(new Date()).format('YYYY-MM-DD'),
before: dayjs(new Date(2 ** 42)).format('YYYY-MM-DD'),
}),
all: () => ({
after: dayjs(new Date(0)).format('YYYY-MM-DD'),
before: dayjs(new Date(2 ** 42)).format('YYYY-MM-DD'),
}),
};
function rangeDates(state) {
return dateRanges[state.range]();
}
function before(state) {
return dateRanges[state.range]().before;
}
function after(state) {
return dateRanges[state.range]().after;
}
export default {
rangeDates,
before,
after,
};

12
assets/js/ui/mutations.js Normal file
View File

@ -0,0 +1,12 @@
function setFilter(state, filter) {
state.filter = filter;
}
function setRange(state, range) {
state.range = range;
}
export default {
setFilter,
setRange,
};

7
assets/js/ui/state.js Normal file
View File

@ -0,0 +1,7 @@
const storedFilter = localStorage.getItem('filter');
const storedRange = localStorage.getItem('range');
export default {
filter: storedFilter ? storedFilter.split(',') : ['gay', 'transsexual'],
range: storedRange || 'new',
};

15
assets/js/ui/ui.js Normal file
View File

@ -0,0 +1,15 @@
import state from './state';
import mutations from './mutations';
import getters from './getters';
import actions from './actions';
function initUiStore(store, router) {
return {
state,
mutations,
getters,
actions: actions(store, router),
};
}
export default initUiStore;

View File

@ -1,24 +1,24 @@
/* $primary: #ff886c; */
.filters[data-v-643133a6] {
.filters[data-v-e35db0d8] {
display: inline-block;
list-style: none;
padding: .5rem;
margin: 0;
}
.filters[data-v-643133a6]:not(:last-child) {
.filters[data-v-e35db0d8]:not(:last-child) {
border-right: solid 1px rgba(0, 0, 0, 0.1);
}
.filter[data-v-643133a6] {
.filter[data-v-e35db0d8] {
display: inline-block;
}
.compact .filters[data-v-643133a6] {
.compact .filters[data-v-e35db0d8] {
padding: 0;
border: none;
}
.compact .filter[data-v-643133a6] {
.compact .filter[data-v-e35db0d8] {
margin: 0 0 1.5rem 0;
}
.toggle[data-v-643133a6] {
.toggle[data-v-e35db0d8] {
color: rgba(0, 0, 0, 0.2);
box-sizing: border-box;
padding: .5rem;
@ -28,19 +28,19 @@
font-weight: bold;
cursor: pointer;
}
.toggle .check[data-v-643133a6] {
.toggle .check[data-v-e35db0d8] {
display: none;
}
.toggle[data-v-643133a6]:hover {
.toggle[data-v-e35db0d8]:hover {
color: rgba(0, 0, 0, 0.5);
}
.toggle.active[data-v-643133a6] {
.toggle.active[data-v-e35db0d8] {
color: #ff6c88;
box-shadow: 0 0 2px rgba(0, 0, 0, 0.2);
}
/* $primary: #ff886c; */
.filter-bar[data-v-a678373a] {
.filter-bar[data-v-6db17c96] {
background: #fff;
display: flex;
justify-content: space-between;
@ -48,19 +48,19 @@
font-size: 0;
box-shadow: 0 0 3px rgba(0, 0, 0, 0.5);
}
.filter-bar .icon[data-v-a678373a] {
.filter-bar .icon[data-v-6db17c96] {
fill: rgba(0, 0, 0, 0.5);
}
.filters-container[data-v-a678373a] {
.filters-container[data-v-6db17c96] {
display: inline-block;
}
.filters-compact[data-v-a678373a] {
.filters-compact[data-v-6db17c96] {
font-size: 1rem;
font-weight: bold;
display: none;
margin: 0 0 0 .5rem;
}
.range-button[data-v-a678373a] {
.range-button[data-v-6db17c96] {
color: rgba(0, 0, 0, 0.5);
background: #fff;
display: inline-block;
@ -70,21 +70,21 @@
font-size: .8rem;
font-weight: bold;
}
.range-button[data-v-a678373a]:hover {
.range-button[data-v-6db17c96]:hover {
color: #222;
cursor: pointer;
}
.range-input[data-v-a678373a] {
.range-input[data-v-6db17c96] {
display: none;
}
.range-input:checked + .range-button[data-v-a678373a] {
.range-input:checked + .range-button[data-v-6db17c96] {
color: #ff6c88;
}
@media (max-width: 720px) {
.filters-container[data-v-a678373a] {
.filters-container[data-v-6db17c96] {
display: none;
}
.filters-compact[data-v-a678373a] {
.filters-compact[data-v-6db17c96] {
display: inline-block;
}
}

View File

@ -77,6 +77,8 @@ function commonQuery(queryBuilder, {
before = new Date(2 ** 44), // May 2109
limit = 100,
}) {
const finalFilter = [].concat(filter); // ensure filter is array
queryBuilder
.leftJoin('sites', 'releases.site_id', 'sites.id')
.leftJoin('studios', 'releases.studio_id', 'studios.id')
@ -93,7 +95,7 @@ function commonQuery(queryBuilder, {
.select('*')
.from('tags_associated')
.leftJoin('tags', 'tags_associated.tag_id', 'tags.id')
.whereIn('tags.slug', filter)
.whereIn('tags.slug', finalFilter)
.andWhereRaw('tags_associated.release_id = releases.id');
})
.andWhere('date', '>', after)

View File

@ -9,13 +9,7 @@ const {
} = require('../releases');
async function fetchReleasesApi(req, res) {
const filter = req.query.filter ? [].concat(req.query.filter) : []; // don't filter for 'undefined'
const releases = await fetchReleases({}, {
filter,
after: req.query.after,
before: req.query.before,
});
const releases = await fetchReleases({}, req.query);
res.send(releases);
}
@ -47,7 +41,7 @@ async function fetchNetworkReleasesApi(req, res) {
const releases = await fetchNetworkReleases({
id: networkId,
slug: networkSlug,
});
}, req.query);
res.send(releases);
}