Files
enfrancais-app/src/pages/library/LibraryList.vue
T

148 lines
3.2 KiB
Vue

<template>
<b-overlay :show="filteredNodes === undefined" class="h-100" z-index="0">
<div class="library-list">
<div class="library-list-container" @click="onContainerClick">
<div v-for="([char, nodes]) in filteredNodes" :key="char">
<h3 :id="char">
{{ char }}
</h3>
<div class="library-list-nodes-group">
<node-view
v-for="node in nodes" :key="char + '-' + node.id"
:node="node"
mode="card"
@click.native.capture="previewNode = node"
:preview="previewNode === node"
@open-node="$emit('open-node', $event)"
@open-child="$emit('open-node', { parentId: node.id, ...$event })"
:style="`--opacity: ${getStrangenessOpacity(strangeness, node)};`"
/>
</div>
</div>
</div>
</div>
</b-overlay>
</template>
<script>
import { mapGetters } from 'vuex'
import { searchInNode, tagsInNode, getStrangenessOpacity } from '@/store/utils'
import { NodeView } from '@/components/nodes'
export default {
name: 'LibraryList',
components: {
NodeView
},
data () {
return {
previewNode: null
}
},
computed: {
...mapGetters(['orderedTextsDepart', 'search', 'tags', 'strangeness']),
filteredNodes () {
if (!this.orderedTextsDepart) return
const nodesGroups = []
const search = this.search.toLowerCase()
this.orderedTextsDepart.forEach(([char, nodes]) => {
const filteredNodes = nodes
.filter(node => tagsInNode(this.tags, node.tags))
.filter(node => searchInNode(search, node))
if (filteredNodes.length) {
nodesGroups.push([char, filteredNodes])
}
})
return nodesGroups
}
},
methods: {
getStrangenessOpacity,
onContainerClick (e) {
if (!e.target.classList.contains('node-view')) {
this.previewNode = null
}
}
},
created () {
this.$store.dispatch('INIT_LIBRARY_LIST')
}
}
</script>
<style lang="scss" scoped>
.library-list {
overflow-y: auto;
height: 100%;
padding: 0 1.15rem;
@include media-breakpoint-up($size-bp) {
padding: 0 2.15rem;
}
h3 {
font-family: $font-family-text;
line-height: 1;
font-size: 6.25rem;
margin-top: 2rem;
@include media-breakpoint-up($size-bp) {
margin-top: 2rem;
font-size: 16.5rem;
}
}
&-nodes-group {
display: grid;
grid-gap: 2.2rem;
grid-template-columns: 1fr;
grid-template-rows: auto;
@include media-breakpoint-up(lg) {
grid-gap: 3.4rem;
}
@media (min-width: 650px) {
grid-template-columns: repeat(2, 1fr);
}
@include media-breakpoint-up(lg) {
grid-template-columns: repeat(3, 1fr);
}
@include media-breakpoint-up(xxl) {
grid-template-columns: repeat(4, 1fr);
}
.node-view {
max-width: 100%;
height: $node-card-height-sm;
@include media-breakpoint-up($size-bp) {
max-width: $node-card-width;
height: $node-card-height;
}
&.preview {
top: -2rem;
}
&:not(.preview) {
opacity: var(--opacity);
}
}
}
}
</style>