2023-12-30 05:29:53 +00:00
< template >
2024-01-10 01:00:38 +00:00
< div
class = "page"
>
< Filters
v - if = "showFilters"
: class = "{ loading }"
>
2024-01-08 01:21:57 +00:00
< TagsFilter
: filters = "filters"
: tags = "aggTags"
@ update = "updateFilter"
/ >
2024-01-09 01:26:32 +00:00
< ChannelsFilter
: filters = "filters"
: channels = "aggChannels"
@ update = "updateFilter"
/ >
2024-01-07 22:44:33 +00:00
< ActorsFilter
: filters = "filters"
2024-01-08 01:21:57 +00:00
: actors = "aggActors"
2024-01-07 22:44:33 +00:00
@ update = "updateFilter"
/ >
2024-01-07 05:13:40 +00:00
< / Filters >
2024-01-10 01:00:38 +00:00
< div
class = "scenes-container"
: class = "{ loading }"
>
2024-01-07 22:44:33 +00:00
< div
v - if = "showMeta"
class = "scenes-header"
>
2024-01-07 05:13:40 +00:00
< div class = "meta" > { { total } } results < / div >
< / div >
< nav class = "scopes" >
< Link
: href = "getPath('latest')"
class = "scope nolink"
: active = "scope === 'latest'"
> Latest < / Link >
< Link
: href = "getPath('upcoming')"
class = "scope nolink"
: active = "scope === 'upcoming'"
> Upcoming < / Link >
< Link
: href = "getPath('new')"
class = "scope nolink"
: active = "scope === 'new'"
> New < / Link >
< / nav >
2024-01-10 01:00:38 +00:00
< ul
class = "scenes nolist"
>
2024-01-07 05:13:40 +00:00
< li
v - for = "scene in scenes"
: key = "scene.id"
>
< Scene :scene ="scene" / >
< / li >
< / ul >
< Pagination / >
< / div >
2024-01-10 01:00:38 +00:00
< Ellipsis
class = "ellipsis"
: class = "{ loading }"
/ >
2023-12-30 05:29:53 +00:00
< / div >
< / template >
< script setup >
2024-01-07 22:44:33 +00:00
import { ref , inject } from 'vue' ;
2024-01-07 05:13:40 +00:00
import { parse } from 'path-to-regexp' ;
import navigate from '#/src/navigate.js' ;
import { get } from '#/src/api.js' ;
import events from '#/src/events.js' ;
2024-01-09 01:26:32 +00:00
import { getActorIdentifier , parseActorIdentifier } from '#/src/query.js' ;
2023-12-30 05:29:53 +00:00
2024-01-07 05:13:40 +00:00
import Filters from '#/components/filters/filters.vue' ;
2024-01-07 22:44:33 +00:00
import ActorsFilter from '#/components/filters/actors.vue' ;
2024-01-08 01:21:57 +00:00
import TagsFilter from '#/components/filters/tags.vue' ;
2024-01-09 01:26:32 +00:00
import ChannelsFilter from '#/components/filters/channels.vue' ;
2024-01-10 01:00:38 +00:00
import Scene from '#/components/scenes/tile.vue' ;
import Pagination from '#/components/pagination/pagination.vue' ;
import Ellipsis from '#/components/loading/ellipsis.vue' ;
2023-12-30 05:29:53 +00:00
defineProps ( {
2024-01-07 05:13:40 +00:00
showFilters : {
type : Boolean ,
default : true ,
2023-12-30 05:29:53 +00:00
} ,
2024-01-07 22:44:33 +00:00
showMeta : {
type : Boolean ,
default : true ,
} ,
2023-12-30 05:29:53 +00:00
} ) ;
2024-01-07 05:13:40 +00:00
const { pageProps , routeParams , urlParsed } = inject ( 'pageContext' ) ;
const { scope } = routeParams ;
const {
2024-01-09 01:26:32 +00:00
actor : pageActor ,
tag : pageTag ,
channel : pageChannel ,
2024-01-07 05:13:40 +00:00
} = pageProps ;
const scenes = ref ( pageProps . scenes ) ;
2024-01-10 01:00:38 +00:00
const aggActors = ref ( pageProps . aggActors || [ ] ) ;
const aggTags = ref ( pageProps . aggTags || [ ] ) ;
const aggChannels = ref ( pageProps . aggChannels || [ ] ) ;
2024-01-07 05:13:40 +00:00
const currentPage = ref ( Number ( routeParams . page ) ) ;
const total = ref ( Number ( pageProps . total ) ) ;
2024-01-10 01:00:38 +00:00
const loading = ref ( false ) ;
2024-01-07 05:13:40 +00:00
2024-01-09 01:26:32 +00:00
const actorIds = urlParsed . search . actors ? . split ( ',' ) . map ( ( identifier ) => parseActorIdentifier ( identifier ) ? . id ) . filter ( Boolean ) || [ ] ;
const queryActors = actorIds . map ( ( urlActorId ) => aggActors . value . find ( ( aggActor ) => aggActor . id === urlActorId ) ) . filter ( Boolean ) ;
const networks = Object . fromEntries ( aggChannels . value . map ( ( channel ) => ( channel . type === 'network' ? channel : channel . parent ) ) . filter ( Boolean ) . map ( ( parent ) => [ ` _ ${ parent . slug } ` , parent ] ) ) ;
const channels = Object . fromEntries ( aggChannels . value . filter ( ( channel ) => channel . type === 'channel' ) . map ( ( channel ) => [ channel . slug , channel ] ) ) ;
2024-01-10 01:00:38 +00:00
const queryEntity = networks [ urlParsed . search . e ] || channels [ urlParsed . search . e ] ;
2024-01-09 01:26:32 +00:00
2024-01-07 05:13:40 +00:00
const filters = ref ( {
2024-01-08 01:21:57 +00:00
tags : urlParsed . search . tags ? . split ( ',' ) . filter ( Boolean ) || [ ] ,
2024-01-10 01:00:38 +00:00
entity : queryEntity ,
2024-01-09 01:26:32 +00:00
actors : queryActors ,
2024-01-07 05:13:40 +00:00
} ) ;
function getPath ( targetScope , preserveQuery ) {
const path = parse ( routeParams . path )
. map ( ( segment ) => {
if ( segment . name === 'scope' ) {
return targetScope ;
}
if ( segment . name === 'page' ) {
return 1 ;
}
return routeParams [ segment . name ] || segment ;
} )
. join ( '/' ) ;
if ( preserveQuery && urlParsed . searchOriginal ) {
return ` ${ path } ${ urlParsed . searchOriginal } ` ;
}
return path ;
}
async function search ( resetPage = true ) {
if ( resetPage ) {
currentPage . value = 1 ;
}
2024-01-09 01:26:32 +00:00
const query = { } ;
2024-01-08 01:21:57 +00:00
2024-01-10 01:00:38 +00:00
const entity = filters . value . entity || pageChannel ;
2024-01-09 01:26:32 +00:00
const entitySlug = entity ? . type === 'network' ? ` _ ${ entity . slug } ` : entity ? . slug ;
2024-01-07 05:13:40 +00:00
2024-01-10 01:00:38 +00:00
loading . value = true ;
2024-01-07 05:13:40 +00:00
const res = await get ( '/scenes' , {
... query ,
2024-01-09 01:26:32 +00:00
actors : [ pageActor , ... filters . value . actors ] . filter ( Boolean ) . map ( ( filterActor ) => getActorIdentifier ( filterActor ) ) . join ( ',' ) , // if we're on an actor page, that actor ID needs to be included
tags : [ pageTag ? . slug , ... filters . value . tags ] . filter ( Boolean ) . join ( ',' ) ,
2024-01-10 01:00:38 +00:00
e : entitySlug ,
2024-01-07 05:13:40 +00:00
scope ,
page : currentPage . value , // client uses param rather than query pagination
} ) ;
scenes . value = res . scenes ;
2024-01-08 01:21:57 +00:00
aggActors . value = res . aggActors ;
aggTags . value = res . aggTags ;
2024-01-10 01:00:38 +00:00
aggChannels . value = res . aggChannels ;
2024-01-07 05:13:40 +00:00
total . value = res . total ;
2024-01-10 01:00:38 +00:00
loading . value = false ;
2024-01-07 05:13:40 +00:00
events . emit ( 'scrollUp' ) ;
navigate ( getPath ( scope , false ) , {
... query ,
2024-01-09 01:26:32 +00:00
actors : filters . value . actors . map ( ( filterActor ) => getActorIdentifier ( filterActor ) ) . join ( ',' ) || undefined , // don't include page actor ID in query, already a parameter
tags : filters . value . tags . join ( ',' ) || undefined ,
2024-01-10 01:00:38 +00:00
e : filters . value . entity ? . type === 'network' ? ` _ ${ filters . value . entity . slug } ` : ( filters . value . entity ? . slug || undefined ) ,
2024-01-07 05:13:40 +00:00
} , { redirect : false } ) ;
}
function updateFilter ( prop , value , reload = true ) {
filters . value [ prop ] = value ;
if ( reload ) {
search ( ) ;
}
}
2023-12-30 05:29:53 +00:00
< / script >
< style scoped >
. page {
2024-01-07 05:13:40 +00:00
display : flex ;
2023-12-30 05:29:53 +00:00
background : var ( -- background - base - 10 ) ;
2024-01-10 01:00:38 +00:00
position : relative ;
2023-12-30 05:29:53 +00:00
}
2024-01-07 05:13:40 +00:00
. scenes - header {
display : flex ;
align - items : center ;
2024-01-10 01:00:38 +00:00
padding : 1 rem 0 .25 rem 3 rem ;
2024-01-07 05:13:40 +00:00
}
. scenes - container {
display : flex ;
flex - direction : column ;
2024-01-07 22:44:33 +00:00
flex - grow : 1 ;
2024-01-07 05:13:40 +00:00
}
. meta {
display : flex ;
flex - grow : 1 ;
justify - content : space - between ;
align - items : center ;
}
2023-12-30 05:29:53 +00:00
. scenes {
display : grid ;
grid - template - columns : repeat ( auto - fill , minmax ( 22 rem , 1 fr ) ) ;
gap : .75 rem .5 rem ;
padding : 1 rem ;
}
. scopes {
margin - left : 1 rem ;
}
. scope {
box - sizing : border - box ;
padding : 1 rem ;
color : var ( -- shadow ) ;
font - size : .9 rem ;
font - weight : bold ;
& . active {
color : var ( -- primary ) ;
font - weight : bold ;
}
}
2024-01-10 01:00:38 +00:00
. loading : not ( . ellipsis ) {
opacity : .3 ;
pointer - events : none ;
}
. ellipsis {
display : none ;
position : absolute ;
top : 1 rem ;
left : 50 % ;
& . loading {
display : flex ;
}
}
2023-12-30 05:29:53 +00:00
< / style >