add search filters to LibraryList and LibraryMap
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
<template>
|
||||
<div class="library-list">
|
||||
<div class="library-list-container">
|
||||
<div v-for="(parents, char) in orderedTextsDepart" :key="char">
|
||||
<div v-for="(parents, char) in filteredNodes" :key="char">
|
||||
<h3>{{ char }}</h3>
|
||||
|
||||
<div class="library-list-nodes-group">
|
||||
<node-view
|
||||
v-for="parent in parents" :key="parent.id"
|
||||
@@ -20,18 +21,32 @@
|
||||
// FIXME let events bubble
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
import { searchInNode } from '@/store/utils'
|
||||
import { NodeView } from '@/components/nodes'
|
||||
|
||||
|
||||
export default {
|
||||
name: 'CardList',
|
||||
name: 'LibraryList',
|
||||
|
||||
components: {
|
||||
NodeView
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapGetters(['orderedTextsDepart'])
|
||||
...mapGetters(['orderedTextsDepart', 'search']),
|
||||
|
||||
filteredNodes () {
|
||||
if (!this.orderedTextsDepart) return {}
|
||||
const nodesGroups = {}
|
||||
const search = this.search.toLowerCase()
|
||||
Object.entries(this.orderedTextsDepart).forEach(([char, nodes]) => {
|
||||
const filteredNodes = nodes.filter(node => searchInNode(search, node))
|
||||
if (filteredNodes.length) {
|
||||
nodesGroups[char] = filteredNodes
|
||||
}
|
||||
})
|
||||
return nodesGroups
|
||||
}
|
||||
},
|
||||
|
||||
created () {
|
||||
|
||||
@@ -2,13 +2,14 @@
|
||||
<b-overlay :show="nodes === undefined" class="h-100">
|
||||
<map-zoom id="library-map" :min-zoom="0.2" :max-zoom="2">
|
||||
<foreignObject
|
||||
v-for="(node, i) in nodes" :key="i"
|
||||
v-for="(node, i) in filteredNodes" :key="i"
|
||||
:style="`--x: ${node.x}px; --y: ${node.y}px; --r: ${node.rotate}deg;`"
|
||||
>
|
||||
<node-view
|
||||
:node="node.data"
|
||||
mode="card"
|
||||
@open-node="onOpen(node.data)"
|
||||
:hidden="node.hidden"
|
||||
/>
|
||||
</foreignObject>
|
||||
</map-zoom>
|
||||
@@ -18,7 +19,9 @@
|
||||
<script>
|
||||
import { randomUniform } from 'd3'
|
||||
import { forceSimulation, forceCollide, forceManyBody } from 'd3-force'
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
import { searchInNode } from '@/store/utils'
|
||||
import { MapZoom } from '@/components/layouts'
|
||||
import { NodeView } from '@/components/nodes'
|
||||
|
||||
@@ -38,6 +41,19 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapGetters(['search']),
|
||||
|
||||
filteredNodes () {
|
||||
if (!this.nodes) return
|
||||
const search = this.search.toLowerCase()
|
||||
this.nodes.forEach(node => {
|
||||
Object.assign(node, { hidden: !searchInNode(search, node.data) })
|
||||
})
|
||||
return this.nodes
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
onOpen (node) {
|
||||
// FIXME ALSO CHECK IF PARENT
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
/>
|
||||
</b-form-group>
|
||||
|
||||
<!-- LIST + MAP ONLY -->
|
||||
<b-form-group
|
||||
v-if="mode !== 'tree'"
|
||||
:label="$t('options.filters.title')"
|
||||
@@ -37,7 +38,20 @@
|
||||
:disabled="true"
|
||||
/>
|
||||
</b-form-group>
|
||||
|
||||
<b-form-group
|
||||
:label="$t('options.search.title')"
|
||||
label-for="search-input"
|
||||
>
|
||||
<b-input-group append="search-icon">
|
||||
<b-form-input
|
||||
v-model="activeSearch" id="search-input" trim
|
||||
/>
|
||||
</b-input-group>
|
||||
</b-form-group>
|
||||
</b-form-group>
|
||||
|
||||
<!-- TREE ONLY -->
|
||||
<b-form-group
|
||||
v-else
|
||||
label="Texte de départ :"
|
||||
@@ -46,24 +60,11 @@
|
||||
>
|
||||
<b-form-select
|
||||
id="text-depart-select"
|
||||
v-model="nodeDepartId"
|
||||
v-model="activeNodeId"
|
||||
:options="nodesDepartsOptions"
|
||||
class="border"
|
||||
/>
|
||||
</b-form-group>
|
||||
|
||||
|
||||
<b-form-group
|
||||
:label="$t('options.search.title')"
|
||||
label-for="search-input"
|
||||
>
|
||||
<b-input-group append="search-icon">
|
||||
<b-form-input
|
||||
v-model="search" id="search-input" trim
|
||||
:disabled="true"
|
||||
/>
|
||||
</b-input-group>
|
||||
</b-form-group>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -87,35 +88,43 @@ export default {
|
||||
{ text: this.$t('options.display.choices.card-list'), value: 'list' }
|
||||
],
|
||||
selectedTags: [],
|
||||
strangeness: 0,
|
||||
textDepartId: undefined,
|
||||
search: ''
|
||||
strangeness: 0
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapGetters(['mode', 'nodebook', 'nodesDepartsOptions', 'tagsOptions']),
|
||||
...mapGetters([
|
||||
'mode',
|
||||
'nodeDepartId',
|
||||
'search',
|
||||
'nodebook',
|
||||
'nodesDepartsOptions',
|
||||
'tagsOptions'
|
||||
]),
|
||||
|
||||
show () {
|
||||
return this.nodebook.length === 0
|
||||
},
|
||||
|
||||
nodeDepartId: {
|
||||
get () {
|
||||
return this.$store.state.library.nodeDepartId
|
||||
},
|
||||
activeNodeId: {
|
||||
get () { return this.nodeDepartId },
|
||||
set (value) {
|
||||
this.$store.dispatch('SET_NODE_DEPART_ID', value)
|
||||
}
|
||||
},
|
||||
|
||||
activeMode: {
|
||||
get () {
|
||||
return this.mode
|
||||
},
|
||||
get () { return this.mode },
|
||||
set (value) {
|
||||
this.$store.dispatch('UPDATE_QUERY_MODE', value)
|
||||
}
|
||||
},
|
||||
|
||||
activeSearch: {
|
||||
get () { return this.search },
|
||||
set (value) {
|
||||
this.$store.commit('SET_SEARCH', value)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,8 @@ export default {
|
||||
nodeDepartId: undefined,
|
||||
trees: {},
|
||||
mode: undefined,
|
||||
nodebook: undefined
|
||||
nodebook: undefined,
|
||||
search: ''
|
||||
},
|
||||
|
||||
mutations: {
|
||||
@@ -67,6 +68,10 @@ export default {
|
||||
|
||||
'SET_NODE_DEPART_ID' (state, id) {
|
||||
state.nodeDepartId = id
|
||||
},
|
||||
|
||||
'SET_SEARCH' (state, str) {
|
||||
state.search = str
|
||||
}
|
||||
},
|
||||
|
||||
@@ -165,7 +170,9 @@ export default {
|
||||
},
|
||||
|
||||
getters: {
|
||||
mode: (state) => state.mode,
|
||||
mode: state => state.mode,
|
||||
nodeDepartId: state => state.nodeDepartId,
|
||||
search: state => state.search,
|
||||
|
||||
nodebook: (state, getters, rootState) => {
|
||||
if (!state.nodebook) return []
|
||||
|
||||
@@ -28,6 +28,8 @@ export const VARIANT_IDS = Object.fromEntries(
|
||||
Object.entries(ID_VARIANTS).map(([key, value]) => [value, key])
|
||||
)
|
||||
|
||||
export const SEARCH_KEYS = ['content', 'title', 'preTitle', 'authors']
|
||||
|
||||
|
||||
export function parseNodesQueryParams ({ mode, nodes = [] }) {
|
||||
let nodebook = typeof nodes === 'string' ? [nodes] : nodes
|
||||
@@ -112,3 +114,20 @@ export function buildTree (treeData, nodesData) {
|
||||
links
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export function searchInNode (search, node) {
|
||||
if (!search) return true
|
||||
for (const key of SEARCH_KEYS) {
|
||||
if (!node[key]) continue
|
||||
let match = false
|
||||
if (key === 'authors') {
|
||||
match = node[key].some(author => author.name.toLowerCase().includes(search))
|
||||
} else {
|
||||
console.log(node[key].toLowerCase(), search)
|
||||
match = node[key].toLowerCase().includes(search)
|
||||
}
|
||||
if (match) return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user