update library opening strategy
This commit is contained in:
@@ -79,4 +79,8 @@ export default {
|
||||
opacity: .25;
|
||||
}
|
||||
}
|
||||
|
||||
#app > header {
|
||||
border-bottom: $line;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -53,8 +53,8 @@ $grid-breakpoints: (
|
||||
xs: 0,
|
||||
sm: 576px,
|
||||
md: 1024px,
|
||||
// lg: 992px,
|
||||
// xl: 1200px
|
||||
lg: 1200px,
|
||||
xl: 1440px,
|
||||
);
|
||||
|
||||
$layout-bp: md;
|
||||
|
||||
+1
-2
@@ -10,8 +10,7 @@ import store from './store'
|
||||
|
||||
Vue.use(BootstrapVue, {
|
||||
BButton: { pill: true },
|
||||
BCardHeader: { headerBgVariant: 'white' },
|
||||
BCardFooter: { footerBgVariant: 'white' }
|
||||
BOverlay: { blur: null, spinnerType: 'grow', opacity: 0 }
|
||||
})
|
||||
Vue.use(Meta)
|
||||
Vue.use(Vue2TouchEvents)
|
||||
|
||||
@@ -41,5 +41,6 @@
|
||||
"siblings": "Textes rebonds",
|
||||
"text": {
|
||||
"read": "Voir le texte"
|
||||
}
|
||||
},
|
||||
"from": "à partir de :"
|
||||
}
|
||||
|
||||
+46
-120
@@ -1,101 +1,55 @@
|
||||
<template>
|
||||
<div class="library">
|
||||
<!-- BACKGROUND (mode) -->
|
||||
<component :is="mode" @open="openText" />
|
||||
<component :is="'library-' + mode" @open-node="openNode" />
|
||||
|
||||
<!-- FOREGROUND (texts) -->
|
||||
<div v-if="parents.length" class="main-texts-container">
|
||||
<section
|
||||
v-for="(parent, i) in parents" :key="parent.id"
|
||||
class="main-text-container text-break"
|
||||
:style="`--n: ${i};`"
|
||||
:class="{ 'text-blur': i !== parents.length - 1 }"
|
||||
>
|
||||
<text-card
|
||||
:id="parent.id"
|
||||
:children="parent.children"
|
||||
class="text-card-main"
|
||||
@open="openText" @close="closeText"
|
||||
@click.native="onMainTextClick(i)"
|
||||
/>
|
||||
|
||||
<section class="sub-texts-container">
|
||||
<text-card
|
||||
v-for="(id, j) in parent.children" :key="id"
|
||||
:id="id"
|
||||
class="text-card-sub text-break"
|
||||
:style="`--n: ${j};`"
|
||||
@close="closeText(parent.id, $event)"
|
||||
@click.native="onSubTextClick(i, j)"
|
||||
/>
|
||||
</section>
|
||||
</section>
|
||||
</div>
|
||||
<!-- FOREGROUND (nodes) -->
|
||||
<node-book
|
||||
v-if="nodebook.length"
|
||||
:nodes="nodebook"
|
||||
class="library-node-book no-events-container"
|
||||
@open-node="openNode"
|
||||
@close-node="closeNode"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { CardList, CardMap, TreeMap } from './library'
|
||||
import TextCard from '@/components/text/TextCard'
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
import {
|
||||
LibraryList,
|
||||
LibraryMap,
|
||||
LibraryTree
|
||||
} from './library'
|
||||
import { NodeBook } from '@/components/layouts'
|
||||
|
||||
|
||||
export default {
|
||||
name: 'Library',
|
||||
|
||||
components: {
|
||||
CardList,
|
||||
CardMap,
|
||||
TreeMap,
|
||||
TextCard
|
||||
LibraryList,
|
||||
LibraryMap,
|
||||
LibraryTree,
|
||||
NodeBook
|
||||
},
|
||||
|
||||
props: {
|
||||
mode: { type: String, required: true },
|
||||
texts: { type: Array, required: true }
|
||||
query: { type: Object, required: true }
|
||||
},
|
||||
|
||||
computed: {
|
||||
parents () {
|
||||
return this.texts.map(text => {
|
||||
const [id, ...children] = text
|
||||
return { id, children }
|
||||
})
|
||||
...mapGetters(['mode', 'nodebook'])
|
||||
},
|
||||
|
||||
watch: {
|
||||
query (query) {
|
||||
this.$store.dispatch('UPDATE_NODEBOOK', query)
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
openText (id, childId) {
|
||||
const parent = this.parents.find(p => p.id === id)
|
||||
if (parent && (childId === undefined || parent.children.includes(childId))) return
|
||||
|
||||
if (!parent) {
|
||||
this.parents.push({ id, children: childId ? [childId] : [] })
|
||||
} else if (childId) {
|
||||
parent.children.push(childId)
|
||||
}
|
||||
this.updateQuery(this.parents)
|
||||
},
|
||||
|
||||
closeText (id, childId) {
|
||||
const parent = this.parents.find(p => p.id === id)
|
||||
if (!childId) {
|
||||
this.updateQuery(this.parents.filter(p => p !== parent))
|
||||
} else {
|
||||
parent.children = parent.children.filter(childId_ => childId_ !== childId)
|
||||
this.updateQuery(this.parents)
|
||||
}
|
||||
},
|
||||
|
||||
updateQuery (parents) {
|
||||
// Update the route's query (will not reload the page) and let vue determine what changed.
|
||||
this.$router.push({
|
||||
query: {
|
||||
mode: this.mode,
|
||||
texts: parents.map(parent => [parent.id, ...parent.children])
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
onMainTextClick (mainTextIndex) {
|
||||
if (mainTextIndex === this.texts.length - 1) return
|
||||
this.parents.push(this.parents.splice(mainTextIndex, 1)[0])
|
||||
@@ -118,7 +72,19 @@ export default {
|
||||
if (needUpdate) {
|
||||
this.updateQuery(this.parents)
|
||||
}
|
||||
},
|
||||
|
||||
openNode (parentId, childId) {
|
||||
this.$store.dispatch('OPEN_NODE', [parentId, childId])
|
||||
},
|
||||
|
||||
closeNode (parentId, childId) {
|
||||
this.$store.dispatch('CLOSE_NODE', [parentId, childId])
|
||||
}
|
||||
},
|
||||
|
||||
created () {
|
||||
this.$store.dispatch('UPDATE_NODEBOOK', this.query)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -126,53 +92,13 @@ export default {
|
||||
<style lang="scss" scoped>
|
||||
.library {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.main-texts-container {
|
||||
position: relative;
|
||||
top: -100%;
|
||||
|
||||
height: 100%;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.main-text-container {
|
||||
border-top: 2px solid $black;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
|
||||
> * {
|
||||
flex-basis: 50%;
|
||||
&-node-book {
|
||||
position: relative;
|
||||
margin-bottom: -100%;
|
||||
// compensate header border
|
||||
height: calc(100% + 2px);
|
||||
top: calc(-100% - 2px);
|
||||
}
|
||||
}
|
||||
|
||||
.sub-texts-container {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.text-card {
|
||||
pointer-events: auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.text-break {
|
||||
position: absolute;
|
||||
height: calc(100% - (var(--n) * #{$text-card-header-height}));
|
||||
top: calc(var(--n) * #{$text-card-header-height});
|
||||
z-index: var(--n);
|
||||
}
|
||||
|
||||
.text-blur::before {
|
||||
content: '';
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba($white, .5);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -6,14 +6,14 @@
|
||||
>
|
||||
<b-form-radio-group
|
||||
id="mode-select"
|
||||
v-model="currentMode" :options="modes"
|
||||
v-model="activeMode" :options="modes"
|
||||
name="mode-select" :aria-describedby="ariaDescribedby"
|
||||
buttons button-variant="outline-dark"
|
||||
/>
|
||||
</b-form-group>
|
||||
|
||||
<b-form-group
|
||||
v-if="currentMode !== 'tree-map'"
|
||||
v-if="mode !== 'tree'"
|
||||
:label="$t('options.filters.title')"
|
||||
>
|
||||
<b-form-group
|
||||
@@ -22,8 +22,7 @@
|
||||
>
|
||||
<multiple-tags-select
|
||||
id="tags-select" :button-text="$t('options.filters.choices.tags')"
|
||||
v-model="selectedTags" :options="tags"
|
||||
:disabled="true"
|
||||
v-model="selectedTags" :options="tagsOptions"
|
||||
/>
|
||||
</b-form-group>
|
||||
|
||||
@@ -80,20 +79,13 @@ export default {
|
||||
MultipleTagsSelect
|
||||
},
|
||||
|
||||
props: {
|
||||
show: { type: Boolean, required: true },
|
||||
mode: { type: String, required: true },
|
||||
tags: { type: Array, default: () => ([]) }
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
modes: [
|
||||
{ text: this.$t('options.display.choices.tree-map'), value: 'tree-map' },
|
||||
{ text: this.$t('options.display.choices.card-map'), value: 'card-map' },
|
||||
{ text: this.$t('options.display.choices.card-list'), value: 'card-list' }
|
||||
{ text: this.$t('options.display.choices.tree-map'), value: 'tree' },
|
||||
{ text: this.$t('options.display.choices.card-map'), value: 'map' },
|
||||
{ text: this.$t('options.display.choices.card-list'), value: 'list' }
|
||||
],
|
||||
currentMode: this.mode,
|
||||
selectedTags: [],
|
||||
strangeness: 0,
|
||||
textDepartId: undefined,
|
||||
@@ -102,7 +94,11 @@ export default {
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapGetters(['nodesDepartsOptions']),
|
||||
...mapGetters(['mode', 'nodebook', 'nodesDepartsOptions', 'tagsOptions']),
|
||||
|
||||
show () {
|
||||
return this.nodebook.length === 0
|
||||
},
|
||||
|
||||
nodeDepartId: {
|
||||
get () {
|
||||
@@ -111,12 +107,15 @@ export default {
|
||||
set (value) {
|
||||
this.$store.dispatch('SET_NODE_DEPART_ID', value)
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
watch: {
|
||||
currentMode (mode) {
|
||||
this.$router.push({ query: { mode } })
|
||||
activeMode: {
|
||||
get () {
|
||||
return this.mode
|
||||
},
|
||||
set (value) {
|
||||
this.$store.dispatch('UPDATE_QUERY_MODE', value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-13
@@ -28,19 +28,7 @@ export default [
|
||||
options: () => import(/* webpackChunkName: "library" */ '@/pages/library/LibraryOptions')
|
||||
},
|
||||
props: {
|
||||
default: ({ query }) => {
|
||||
let { mode = 'tree-map', texts = [] } = query
|
||||
if (typeof texts === 'string') texts = [texts]
|
||||
// In case of a reload or direct link, vue-router doesn't turn the query string into an array.
|
||||
if (texts && texts.length && typeof texts[0] === 'string') {
|
||||
texts = texts.map(text => text.split(',').map(id => parseInt(id)))
|
||||
}
|
||||
return { mode, texts }
|
||||
},
|
||||
options: ({ query }) => ({
|
||||
show: !('texts' in query && query.texts.length),
|
||||
mode: query.mode || 'tree-map'
|
||||
})
|
||||
default: ({ query }) => ({ query })
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import Vue from 'vue'
|
||||
import router from '@/router'
|
||||
|
||||
import api from '@/api'
|
||||
import {
|
||||
AllTags
|
||||
} from '@/api/queries'
|
||||
import {
|
||||
parseNodesQueryParams,
|
||||
getUniqueNodesIds,
|
||||
getRelatedNodesIds,
|
||||
buildTree
|
||||
@@ -16,10 +18,38 @@ export default {
|
||||
tags: undefined,
|
||||
strangeness: [0, 1, 2, 3, 4],
|
||||
nodeDepartId: undefined,
|
||||
trees: {}
|
||||
trees: {},
|
||||
mode: undefined,
|
||||
nodebook: undefined
|
||||
},
|
||||
|
||||
mutations: {
|
||||
'SET_MODE' (state, mode) {
|
||||
state.mode = mode
|
||||
},
|
||||
|
||||
'SET_NODEBOOK' (state, nodes) {
|
||||
state.nodebook = nodes
|
||||
},
|
||||
|
||||
'ADD_NODEBOOK_NODE' (state, [stack, parentId, childId]) {
|
||||
console.log('ADD_NODEBOOK_NODE', stack, parentId, childId)
|
||||
if (stack === undefined) {
|
||||
stack = childId === undefined ? [parentId] : [parentId, childId]
|
||||
state.nodebook.push(stack)
|
||||
} else {
|
||||
stack.push(childId)
|
||||
}
|
||||
},
|
||||
|
||||
'REMOVE_NODEBOOK_NODE' (state, [stack, nodeId]) {
|
||||
if (stack[0] === nodeId) {
|
||||
state.nodebook.splice(state.nodebook.indexOf(stack), 1)
|
||||
} else {
|
||||
stack.splice(stack.indexOf(nodeId), 1)
|
||||
}
|
||||
},
|
||||
|
||||
'SET_TAGS' (state, tags) {
|
||||
state.tags = tags
|
||||
},
|
||||
@@ -34,9 +64,30 @@ export default {
|
||||
},
|
||||
|
||||
actions: {
|
||||
async 'UPDATE_NODEBOOK' ({ state, commit, dispatch }, query) {
|
||||
const { mode = 'tree', nodebook } = parseNodesQueryParams(query)
|
||||
commit('SET_MODE', mode)
|
||||
await dispatch('GET_NODES', { ids: [].concat(...nodebook), dataLevel: 'full' })
|
||||
commit('SET_NODEBOOK', nodebook)
|
||||
},
|
||||
|
||||
'UPDATE_QUERY_NODES' ({ state }, from) {
|
||||
const query = {
|
||||
mode: state.mode,
|
||||
nodes: [...state.nodebook.map(ids => ids.join(','))]
|
||||
}
|
||||
router.push({ query })
|
||||
},
|
||||
|
||||
'UPDATE_QUERY_MODE' (store, mode) {
|
||||
if (router.currentRoute.query.mode === mode) return
|
||||
router.push({ query: { mode } })
|
||||
},
|
||||
|
||||
async 'INIT_LIBRARY' ({ state, commit, dispatch, rootState }) {
|
||||
const departIds = await dispatch('GET_ALL_NODES_IDS', 'depart')
|
||||
await dispatch('GET_NODES', { ids: departIds, dataLevel: 'initial' })
|
||||
dispatch('GET_ALL_TAGS')
|
||||
return departIds
|
||||
},
|
||||
|
||||
@@ -78,12 +129,42 @@ export default {
|
||||
}
|
||||
|
||||
return getters.nodeTree
|
||||
},
|
||||
|
||||
async 'OPEN_NODE' ({ state, commit, dispatch }, [parentId, childId]) {
|
||||
const stack = state.nodebook.find(stack => stack[0] === parentId)
|
||||
if (stack && (childId === undefined || stack.includes(childId))) return
|
||||
commit('ADD_NODEBOOK_NODE', [stack, parentId, childId])
|
||||
dispatch('UPDATE_QUERY_NODES')
|
||||
},
|
||||
|
||||
'CLOSE_NODE' ({ state, commit, dispatch }, [parentId, childId]) {
|
||||
const stack = state.nodebook.find(stack => stack.includes(parentId) && (childId ? stack.includes(childId) : true))
|
||||
commit('REMOVE_NODEBOOK_NODE', [stack, childId || parentId])
|
||||
dispatch('UPDATE_QUERY_NODES')
|
||||
}
|
||||
},
|
||||
|
||||
getters: {
|
||||
mode: (state) => state.mode,
|
||||
|
||||
nodebook: (state, getters, rootState) => {
|
||||
if (!state.nodebook) return []
|
||||
return state.nodebook.map(([parentId, ...childrenIds]) => {
|
||||
return {
|
||||
parent: rootState.nodes[parentId],
|
||||
children: childrenIds.map(id => rootState.nodes[id])
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
activeNodes: (state) => {
|
||||
if (!state.nodebook) return []
|
||||
return state.nodebook.reduce((acc, ids) => [...acc, ...ids], [])
|
||||
},
|
||||
|
||||
tagsOptions: state => {
|
||||
if (state.tags === undefined) return
|
||||
if (state.tags === undefined) return []
|
||||
return state.tags.map(tag => ({ value: tag.id, text: tag.name }))
|
||||
},
|
||||
|
||||
|
||||
@@ -29,6 +29,17 @@ export const VARIANT_IDS = Object.fromEntries(
|
||||
)
|
||||
|
||||
|
||||
export function parseNodesQueryParams ({ mode, nodes = [] }) {
|
||||
let nodebook = typeof nodes === 'string' ? [nodes] : nodes
|
||||
nodebook = nodebook.map(ids => {
|
||||
return typeof ids === 'string'
|
||||
? ids.split(',').map(id => parseInt(id))
|
||||
: [...ids]
|
||||
})
|
||||
return { mode, nodebook }
|
||||
}
|
||||
|
||||
|
||||
export function getUniqueNodesIds (tree) {
|
||||
function extractId (ids, node) {
|
||||
ids.add(node.id)
|
||||
|
||||
Reference in New Issue
Block a user