Improved scenes and movies meta header layout and responsiveness.
This commit is contained in:
@@ -15,6 +15,7 @@ import Filters from '#/components/filters/filters.vue';
|
||||
import GroupsFilter from '#/components/filters/groups.vue';
|
||||
|
||||
import TagsFilter from '#/components/filters/tags.vue';
|
||||
import FilterToggle from '#/components/filters/toggle.vue';
|
||||
import YearsFilter from '#/components/filters/years.vue';
|
||||
import Ellipsis from '#/components/loading/ellipsis.vue';
|
||||
import Pagination from '#/components/pagination/pagination.vue';
|
||||
@@ -74,6 +75,11 @@ const total = ref(Number(pageProps.sceneTotal || pageProps.total));
|
||||
const loading = ref(false);
|
||||
const scenesContainer = ref(null);
|
||||
|
||||
// desktop defaults to open, compact defaults to closed
|
||||
// we can't measure the viewport in SSR, so use separate toggles, each viewport only reads its own
|
||||
const showFiltersFull = ref(true);
|
||||
const showFiltersCompact = ref(false);
|
||||
|
||||
const view = ref(env.scenesView || 'grid');
|
||||
|
||||
const actorIds = urlParsed.search.actors?.split(',').map((identifier) => parseActorIdentifier(identifier)?.id).filter(Boolean) || [];
|
||||
@@ -97,6 +103,20 @@ const filters = ref({
|
||||
trans: parseRange(urlParsed.search.trans),
|
||||
});
|
||||
|
||||
// the search input updates the filter while typing, only count the search once it's applied
|
||||
const appliedSearch = ref(urlParsed.search.q);
|
||||
|
||||
// indicates the results are narrowed down: the search, each tag, actor and the channel count individually, each range counts once
|
||||
// the page's own actor, tag or channel aren't in these filters, so they aren't counted
|
||||
const filterCount = computed(() => [
|
||||
appliedSearch.value?.trim() ? 1 : 0,
|
||||
filters.value.tags.length,
|
||||
filters.value.actors.length,
|
||||
filters.value.entity ? 1 : 0,
|
||||
filters.value.years.length > 0 || filters.value.yearRange ? 1 : 0,
|
||||
...['group', 'females', 'males', 'trans'].map((key) => (filters.value[key] ? 1 : 0)),
|
||||
].reduce((acc, count) => acc + count, 0));
|
||||
|
||||
const sceneCampaign = campaigns?.scenes;
|
||||
const campaignIndex = campaigns?.index;
|
||||
|
||||
@@ -123,6 +143,8 @@ function getPath(targetScope, preserveQuery) {
|
||||
}
|
||||
|
||||
async function search(options = {}) {
|
||||
appliedSearch.value = filters.value.search;
|
||||
|
||||
if (options.resetPage !== false) {
|
||||
currentPage.value = 1;
|
||||
}
|
||||
@@ -196,6 +218,11 @@ function updateFilter(prop, value, reload = true) {
|
||||
}
|
||||
}
|
||||
|
||||
function toggleFilters(state) {
|
||||
showFiltersFull.value = state ?? !showFiltersFull.value;
|
||||
showFiltersCompact.value = state ?? !showFiltersCompact.value;
|
||||
}
|
||||
|
||||
function setView(newView) {
|
||||
view.value = newView;
|
||||
Cookies.set('scenesView', newView);
|
||||
@@ -211,6 +238,9 @@ function setView(newView) {
|
||||
<Filters
|
||||
v-if="showFilters"
|
||||
:loading="loading"
|
||||
:show-full="showFiltersFull"
|
||||
:show-compact="showFiltersCompact"
|
||||
@close="toggleFilters(false)"
|
||||
>
|
||||
<div class="filter search-container">
|
||||
<!-- onsearch not compatible with FF and Safari -->
|
||||
@@ -274,16 +304,34 @@ function setView(newView) {
|
||||
class="scenes-container"
|
||||
:class="{ loading }"
|
||||
>
|
||||
<Campaign
|
||||
v-if="campaigns?.meta"
|
||||
:campaign="campaigns.meta"
|
||||
class="campaign-meta campaign-full"
|
||||
/>
|
||||
|
||||
<div
|
||||
v-if="showMeta"
|
||||
class="scenes-header"
|
||||
>
|
||||
<div class="meta">{{ total }} results</div>
|
||||
<span class="header-filter">
|
||||
<FilterToggle
|
||||
v-if="showFilters"
|
||||
:show-full="showFiltersFull"
|
||||
:show-compact="showFiltersCompact"
|
||||
:count="filterCount"
|
||||
@toggle="toggleFilters()"
|
||||
/>
|
||||
|
||||
<div
|
||||
class="meta"
|
||||
>{{ total }}<span class="meta-label"> results</span></div>
|
||||
</span>
|
||||
|
||||
<Campaign
|
||||
v-if="campaigns?.meta"
|
||||
:campaign="campaigns.meta"
|
||||
class="campaign-meta"
|
||||
class="campaign-meta campaign-gap"
|
||||
/>
|
||||
|
||||
<div class="views">
|
||||
@@ -430,12 +478,12 @@ function setView(newView) {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
justify-content: space-between;
|
||||
padding: .5rem 1rem .25rem 4rem;
|
||||
padding: .5rem 1rem .5rem 0;
|
||||
|
||||
.campaign {
|
||||
max-height: 6rem;
|
||||
justify-content: center;
|
||||
margin: .5rem 1rem 0 1rem;
|
||||
margin: 0 1rem;
|
||||
/* makes empty area link to ad, bit too annoying
|
||||
width: 0;
|
||||
flex-grow: 1;
|
||||
@@ -455,7 +503,13 @@ function setView(newView) {
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
flex-shrink: 0;
|
||||
margin-bottom: .5rem;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.header-filter {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.scenes-items {
|
||||
@@ -476,6 +530,14 @@ function setView(newView) {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.campaign-full {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.campaign-full {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.campaign-scene {
|
||||
width: 100%;
|
||||
aspect-ratio: 2 / 1; /* ensures banner can't be taller than scene tile */
|
||||
@@ -579,6 +641,14 @@ function setView(newView) {
|
||||
.scopes .views {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.campaign-gap {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.campaign-full {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
@media(--small-20) {
|
||||
@@ -600,4 +670,10 @@ function setView(newView) {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
}
|
||||
|
||||
@media(--small-50) {
|
||||
.meta-label {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user