<template> <div class="releases"> <h3 v-if="context" class="heading" ><span class="range">{{ range }}</span> releases for '{{ context }}'</h3> <Ellipsis v-if="!done" /> <ul v-else-if="releases.length > 0" :key="sfw" class="nolist tiles" > <template v-for="(item, index) in items"> <li v-if="item === 'campaign'" :key="`campaign-${index}`" class="campaign" > <Campaign v-if="item === 'campaign'" :entity="entity" :min-ratio="0.75" :max-ratio="1.25" :allow-generic="true" /> </li> <li v-else :key="`release-${item.id}`" > <SceneTile :release="item" :referer="referer" :index="index" :stash="stash" @stash="isStashed => $emit('stash', isStashed)" /> </li> </template> </ul> <span v-else-if="releases.length === 0 && range !== 'all'" class="empty" >No {{ range }} releases</span> <span v-else-if="releases.length === 0" class="empty" >No recent or upcoming releases</span> </div> </template> <script setup> import config from 'config'; import { defineProps, defineEmits, computed, } from 'vue'; import { useStore } from 'vuex'; import { useRouter } from 'vue-router'; import Campaign from '../campaigns/campaign.vue'; import Ellipsis from '../loading/ellipsis.vue'; import SceneTile from './scene-tile.vue'; const router = useRouter(); const store = useStore(); defineEmits(['stash']); const props = defineProps({ releases: { type: Array, default: () => [], }, entity: { type: Object, default: null, }, context: { type: String, default: null, }, done: { type: Boolean, default: true, }, referer: { type: String, default: null, }, stash: { type: Object, default: null, }, }); const campaignIndex = computed(() => Math.floor(Math.random() * props.releases.length - 5) + 5); const items = computed(() => props.releases.flatMap((release, index) => (config.campaigns.tiles && props.releases.length > 10 && index === campaignIndex.value ? ['campaign', release] : release))); const range = computed(() => router.route?.params.range); const sfw = computed(() => store.state.ui.sfw); </script> <style lang="scss" scoped> @import 'breakpoints'; .heading { padding: 0; margin: 0 0 1rem 0; .range { text-transform: capitalize; } } .releases { flex-grow: 1; border-top: solid 1px var(--crease); &.embedded { border: none; .tiles { padding: 0; } } } .tiles { width: 100%; display: grid; grid-template-columns: repeat(auto-fill, minmax(22rem, 1fr)); grid-gap: .5rem; box-sizing: border-box; padding: 1rem; } .empty { display: inline-block; padding: 1rem; color: var(--shadow-strong); font-weight: bold; } .campaign { display: flex; align-items: flex-start; justify-content: center; } @media(max-width: $breakpoint-mega) { .tiles { grid-template-columns: repeat(auto-fill, minmax(19rem, 1fr)); } } @media(max-width: $breakpoint-kilo) { .tiles { grid-template-columns: repeat(auto-fill, minmax(18.5rem, 1fr)); grid-gap: .5rem; padding: .5rem; } } @media(max-width: $breakpoint) { .tiles { grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr)); } } @media(max-width: $breakpoint-micro) { .tiles { grid-template-columns: repeat(auto-fill, minmax(17rem, 1fr)); } } </style>