traxxx/assets/components/album/album.vue

258 lines
4.4 KiB
Vue

<template>
<teleport to="body">
<div class="album">
<div class="album-header">
<h3 class="album-title">{{ title }}</h3>
<Icon
icon="cross2"
class="close"
@click.native="$emit('close')"
/>
</div>
<div
class="album-items"
:class="{ portrait }"
>
<div
v-for="item in albumItems"
:key="item.id"
class="item-container"
>
<a
:href="getPath(item, null, { local })"
class="item-link"
target="_blank"
>
<img
:src="getPath(item, 'thumbnail', { local })"
:style="{ 'background-image': `url('${getPath(item, 'lazy', { local })}')` }"
:width="item.width"
:height="item.height"
:title="item.title"
loading="lazy"
class="item image"
>
<Logo :photo="item" />
<router-link
v-if="comments && item.title && item.entity"
:to="`/${item.entity.type}/${item.entity.slug}`"
class="item-comment"
>{{ item.title }} for {{ item.entity.name }}</router-link>
<span
v-else-if="comments && item.title"
class="item-comment"
>{{ item.title }}</span>
</a>
</div>
</div>
</div>
</teleport>
</template>
<script>
import Logo from './logo.vue';
function albumItems() {
return this.items
.filter(Boolean)
.map(item => ({
...item,
title: item.comment || (item.credit && `© ${item.credit}`) || (item.entity && `© ${item.entity.name}`),
}));
}
export default {
components: {
Logo,
},
props: {
items: {
type: Array,
default: () => [],
},
title: {
type: String,
default: null,
},
local: {
type: Boolean,
default: false,
},
portrait: {
type: Boolean,
default: false,
},
comments: {
type: Boolean,
default: true,
},
},
computed: {
albumItems,
},
emits: ['close'],
};
</script>
<style lang="scss" scoped>
@import 'breakpoints';
.album {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
position: fixed;
top: 0;
left: 0;
background: var(--darken-extreme);
z-index: 10;
}
.album-header {
display: flex;
justify-content: space-between;
flex-shrink: 0;
}
.album-title {
display: block;
flex-grow: 1;
align-items: center;
padding: 1rem;
margin: 0;
color: var(--text-light);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
text-align: center;
text-transform: capitalize;
}
.close {
width: 1.5rem;
height: 1.5rem;
padding: 1rem;
fill: var(--lighten);
&:hover {
cursor: pointer;
fill: var(--text-light);
}
}
.album-items {
display: grid;
align-items: center;
justify-content: center;
grid-template-columns: repeat(auto-fit, minmax(25rem, 1fr));
grid-gap: 0 1rem;
padding: 1rem;
margin: auto 0;
overflow-y: auto;
&.portrait {
grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
}
}
.item-container {
display: flex;
align-items: center;
justify-content: center;
}
.item-link {
position: relative;
margin: 0 0 .5rem 0;
overflow: hidden;
&:hover {
.item-comment {
transform: translateY(0);
}
::v-deep(.album-logo) {
opacity: 0;
}
}
}
.item {
max-width: 100%;
max-height: 100%;
height: auto;
background-size: cover;
background-position: center;
}
.item-comment {
width: 100%;
position: absolute;
bottom: 0;
left: 0;
box-sizing: border-box;
padding: .5rem;
color: var(--text-light);
background: var(--darken);
font-size: .9rem;
text-shadow: 0 0 3px var(--darken);
text-decoration: none;
white-space: normal;
line-height: 1.25;
transform: translateY(100%);
transition: transform .25s ease;
}
@media(max-width: $breakpoint-giga) {
.album-items {
grid-template-columns: repeat(auto-fill, minmax(22.5rem, 1fr));
.portrait {
grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr));
}
}
}
@media(max-width: $breakpoint-mega) {
.album-items.portrait {
grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr));
}
}
@media(max-width: $breakpoint-kilo) {
.album-items {
grid-template-columns: repeat(auto-fill, minmax(18rem, 1fr));
grid-gap: 0 .5rem;
padding: .5rem;
}
.item-link {
margin: 0 0 .25rem 0;
}
}
@media(max-width: $breakpoint) {
.album-items {
grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
}
}
@media(max-width: $breakpoint-micro) {
.album-items {
grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
}
}
@media(max-width: $breakpoint-pico) {
.album-items {
grid-template-columns: repeat(auto-fill, minmax(7rem, 1fr));
}
}
</style>