<template> <div v-if="entity" class="entity content" > <div class="info"> <a :href="entityUrl" target="_blank" rel="noopener" class="link link-child" > <template v-if="entity.hasLogo"> <img v-if="$route.name === 'network'" class="logo logo-child" :src="`/img/logos/${entity.slug}/thumbs/network.png`" > <img v-else-if="entity.parent && !entity.independent" class="logo logo-child" :src="`/img/logos/${entity.parent.slug}/thumbs/${entity.slug}.png`" > <img v-else class="logo logo-child" :src="`/img/logos/${entity.slug}/thumbs/${entity.slug}.png`" > </template> <h2 v-else class="name" >{{ entity.name }}</h2> <Icon v-if="entity.url" icon="share2" /> </a> <ul v-if="entity.tags.length > 0" class="tags" > <li v-for="tag in entity.tags" :key="`tag-${tag.slug}`" >{{ tag.name }}</li> </ul> <RouterLink v-if="entity.parent" :to="`/${entity.parent.type}/${entity.parent.slug}`" class="link link-parent" > <img v-if="entity.parent.hasLogo" class="logo logo-parent" :src="`/img/logos/${entity.parent.slug}/thumbs/network.png`" > <img v-if="entity.parent.hasLogo" class="favicon" :src="`/img/logos/${entity.parent.slug}/favicon.png`" > <h3 v-else class="name parent-name" >{{ entity.parent.name }}</h3> <Icon icon="device_hub" /> </RouterLink> </div> <div class="content-inner" @scroll="events.emit('scroll', $event)" > <Scroll v-if="entity.children.length > 0" v-slot="scroll" :expandable="true" :expanded="expanded" class="scroll-light" @expand="(state) => expanded = state" > <Children :entity="entity" :class="{ expanded }" @load="scroll.loaded" /> </Scroll> <div v-if="config.campaigns.entity" class="campaign-container" > <Campaign :entity="entity" :min-ratio="3" /> </div> <FilterBar ref="filter" :fetch-releases="fetchEntity" :items-total="totalCount" :items-per-page="limit" :available-tags="entity.tags" /> <div class="releases"> <Releases :releases="entity.releases" :entity="entity" :done="done" /> <Pagination :items-total="totalCount" :items-per-page="limit" class="pagination-top" /> </div> <Footer /> </div> </div> </template> <script> import config from 'config'; import FilterBar from '../filters/filter-bar.vue'; import Pagination from '../pagination/pagination.vue'; import Releases from '../releases/releases.vue'; import Children from './children.vue'; import Scroll from '../scroll/scroll.vue'; import Campaign from '../campaigns/campaign.vue'; async function fetchEntity(scroll = true) { this.done = false; this.entityUrl = null; const { entity, totalCount } = await this.$store.dispatch('fetchEntityBySlugAndType', { entitySlug: this.$route.params.entitySlug, entityType: this.$route.name, limit: this.limit, range: this.$route.params.range, pageNumber: Number(this.$route.params.pageNumber), }); this.entity = entity; this.totalCount = totalCount; this.pageTitle = entity.name; const campaign = entity.campaigns.find((campaignX) => !campaignX.banner) || entity.parent?.campaigns.find((campaignX) => !campaignX.banner); if (entity.url) { const { searchParams, pathname, origin } = new URL(entity.url); const affiliateParams = new URLSearchParams({ ...(entity.url && Object.fromEntries(searchParams)), // preserve any query in entity URL, e.g. ?siteId=5 ...(campaign?.affiliate?.parameters && Object.fromEntries(new URLSearchParams(campaign.affiliate.parameters))), // append affiliate parameters }).toString(); this.entityUrl = campaign?.url || campaign?.affiliate?.url || `${origin}${pathname}${campaign?.affiliate?.parameters ? `?${affiliateParams}` : ''}`; } this.done = true; if (scroll && this.$refs.filter?.$el) { this.$refs.filter.$el.scrollIntoView(); } } async function mounted() { await this.fetchEntity(); } async function route(to) { if (to.name === 'channel' || to.name === 'network' || to.name === 'studio') { await this.fetchEntity(); this.expanded = false; } } export default { components: { FilterBar, Pagination, Children, Releases, Scroll, Campaign, }, data() { return { entity: null, pageTitle: null, totalCount: null, done: false, limit: Number(this.$route.query.limit || 30) - config.campaigns.tiles, // reserve one campaign spot expanded: false, entityUrl: null, }; }, watch: { $route: route, '$store.state.ui.tagFilter': fetchEntity, }, mounted, methods: { fetchEntity, }, }; </script> <style lang="scss" scoped> @import 'breakpoints'; .info { display: flex; justify-content: space-between; background: var(--profile); border-bottom: solid 1px var(--lighten-hint); } .link { max-width: 15rem; display: flex; align-items: center; box-sizing: border-box; padding: 1rem; text-decoration: none; } .link-child { flex-shrink: 0; .icon { fill: var(--lighten); margin: 0 0 0 1rem; } &:hover .icon { fill: var(--text-light); } } .link-parent { flex-direction: row-reverse; flex-shrink: 0; margin: 0 0 0 3rem; .icon { width: 1.25rem; height: 1.25rem; fill: var(--lighten); margin: 0 .5rem 0 0; } } .logo { height: 100%; max-width: 100%; object-fit: contain; } .logo-child { height: 3rem; } .logo-parent { height: 1.5rem; } .favicon { height: 1rem; flex-shrink: 0; } .content-inner { display: flex; flex-direction: column; } .scroll { background: var(--profile); } .campaign-container { max-height: 150px; background: var(--background-dim); text-align: center; padding: .5rem; } .releases { flex-grow: 1; } .name { color: var(--text-light); display: flex; align-items: center; padding: 0; margin: 0; white-space: nowrap; font-size: 1.5rem; } .favicon { display: none; } @media(max-width: $breakpoint) { .tags { display: none; } } @media(max-width: $breakpoint-micro) { .logo-parent { display: none; } .favicon { display: inline-block; } } @media(max-width: $breakpoint-nano) { .link-child .icon { display: none; } } </style>