mirror of
https://github.com/requarks/wiki.git
synced 2025-02-25 18:55:30 -06:00
feat: New tree navigation replaces browse navigation
This commit is contained in:
parent
e3d94f7177
commit
40f875e085
@ -23,6 +23,15 @@
|
||||
v-toolbar-title.subtitle-1 {{$t('admin:navigation.mode')}}
|
||||
v-list(nav, two-line)
|
||||
v-list-item-group(v-model='config.mode', mandatory, :color='$vuetify.theme.dark ? `teal lighten-3` : `teal`')
|
||||
v-list-item(value='NEWTREE')
|
||||
v-list-item-avatar
|
||||
img(src='/_assets/svg/icon-tree-structure-dotted.svg', alt='Site Tree')
|
||||
v-list-item-content
|
||||
v-list-item-title {{$t('admin:navigation.modeNewSiteTree.title')}}
|
||||
v-list-item-subtitle {{$t('admin:navigation.modeNewSiteTree.description')}}
|
||||
v-list-item-avatar
|
||||
v-icon(v-if='$vuetify.theme.dark', :color='config.mode === `NEWTREE` ? `teal lighten-3` : `grey darken-2`') mdi-check-circle
|
||||
v-icon(v-else, :color='config.mode === `NEWTREE` ? `teal` : `grey lighten-3`') mdi-check-circle
|
||||
v-list-item(value='TREE')
|
||||
v-list-item-avatar
|
||||
img(src='/_assets/svg/icon-tree-structure-dotted.svg', alt='Site Tree')
|
||||
|
@ -23,6 +23,15 @@
|
||||
depressed
|
||||
:color='$vuetify.theme.dark ? `grey darken-4` : `blue darken-2`'
|
||||
style='flex: 1 1 100%;'
|
||||
@click='switchMode(`tree`)'
|
||||
)
|
||||
v-icon(left) mdi-file-tree
|
||||
.body-2.text-none {{$t('common:sidebar.tree')}}
|
||||
v-btn.ml-3(
|
||||
v-else-if='currentMode === `tree`'
|
||||
depressed
|
||||
:color='$vuetify.theme.dark ? `grey darken-4` : `blue darken-2`'
|
||||
style='flex: 1 1 100%;'
|
||||
@click='switchMode(`custom`)'
|
||||
)
|
||||
v-icon(left) mdi-navigation
|
||||
@ -43,6 +52,29 @@
|
||||
v-list-item-title {{ item.l }}
|
||||
v-divider.my-2(v-else-if='item.k === `divider`')
|
||||
v-subheader.pl-4(v-else-if='item.k === `header`') {{ item.l }}
|
||||
|
||||
//-> Tree Navigation
|
||||
v-treeview(
|
||||
v-else-if='currentMode === `tree`'
|
||||
activatable
|
||||
open-on-click
|
||||
:color='"white"'
|
||||
:active='treeDefaultActive'
|
||||
:open='treeDefaultOpen'
|
||||
:items='treeItems'
|
||||
:load-children='fetchTreeChild'
|
||||
@update:active='activeTreeItem'
|
||||
)
|
||||
template(v-slot:prepend="{ item, open }")
|
||||
v-icon(v-if="!item.children") mdi-text-box
|
||||
v-icon(v-else-if="open") mdi-folder-open
|
||||
v-icon(v-else) mdi-folder
|
||||
template(v-slot:label="{ item }")
|
||||
div(class='tree-item')
|
||||
a(v-if="!item.children" :href="'/'+item.locale+'/'+item.path")
|
||||
span {{item.name}}
|
||||
span(v-else) {{item.name}}
|
||||
|
||||
//-> Browse
|
||||
v-list.py-2(v-else-if='currentMode === `browse`', dense, :class='color', :dark='dark')
|
||||
template(v-if='currentParent.id > 0')
|
||||
@ -102,7 +134,10 @@ export default {
|
||||
title: '/ (root)'
|
||||
},
|
||||
parents: [],
|
||||
loadedCache: []
|
||||
loadedCache: [],
|
||||
treeItems: [],
|
||||
treeDefaultOpen: [],
|
||||
treeDefaultActive: [],
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@ -116,6 +151,9 @@ export default {
|
||||
if (mode === `browse` && this.loadedCache.length < 1) {
|
||||
this.loadFromCurrentPath()
|
||||
}
|
||||
if (mode === 'tree') {
|
||||
this.fetchTreeRoot();
|
||||
}
|
||||
},
|
||||
async fetchBrowseItems (item) {
|
||||
this.$store.commit(`loadingStart`, 'browse-load')
|
||||
@ -219,7 +257,95 @@ export default {
|
||||
},
|
||||
goHome () {
|
||||
window.location.assign(siteLangs.length > 0 ? `/${this.locale}/home` : '/')
|
||||
}
|
||||
},
|
||||
pageItem2TreeItem(item,level) {
|
||||
if (item.isFolder) {
|
||||
return { id: item.id, level: level, pageId: item.pageId, path: item.path, locale: item.locale, name: item.title, children: [] }
|
||||
} else {
|
||||
return { id: item.id, level: level, path: item.path, locale: item.locale, name: item.title }
|
||||
}
|
||||
},
|
||||
activeTreeItem(id) {
|
||||
const find = (items) => {
|
||||
for(const item of items) {
|
||||
if(item.id == id) {
|
||||
return item
|
||||
}
|
||||
if(item.children && item.children.length) {
|
||||
const v = find(item.children)
|
||||
if(v) {
|
||||
return v
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const item = find(this.treeItems)
|
||||
if(item) {
|
||||
if(!this.treeDefaultActive.includes(item.id)) {
|
||||
location.href = `/${item.locale}/${item.path}`
|
||||
} else {
|
||||
setTimeout(() => {
|
||||
const el = document.querySelector(".v-treeview-node--active")
|
||||
el.scrollIntoViewIfNeeded()
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
async fetchTreeChild(parent) {
|
||||
const items = await this.fetchPages(parent.id)
|
||||
parent.children = []
|
||||
if(parent.pageId){
|
||||
parent.children.push({
|
||||
id: parent.pageId,level: parent.level+1, path: parent.path, locale: parent.locale, name: parent.name
|
||||
})
|
||||
}
|
||||
parent.children.push(
|
||||
...items.map(item => this.pageItem2TreeItem(item, parent.level+1))
|
||||
)
|
||||
this.checkTreeDefaultOpen(parent.children);
|
||||
},
|
||||
async fetchTreeRoot(){
|
||||
const children = await this.fetchPages(0)
|
||||
this.treeItems = children.map(item => this.pageItem2TreeItem(item, 0))
|
||||
this.checkTreeDefaultOpen(this.treeItems, 0);
|
||||
},
|
||||
async checkTreeDefaultOpen(items){
|
||||
const item = items.find(item => item.children && this.path.startsWith(item.path))
|
||||
if(item) {
|
||||
setTimeout(()=>{
|
||||
this.treeDefaultOpen.push(item.id)
|
||||
})
|
||||
}
|
||||
const active = items.find(item => item.path == this.path)
|
||||
if(active) {
|
||||
this.treeDefaultActive.push(active.id)
|
||||
}
|
||||
},
|
||||
async fetchPages(id) {
|
||||
const resp = await this.$apollo.query({
|
||||
query: gql`
|
||||
query($parent: Int, $locale: String!) {
|
||||
pages {
|
||||
tree(parent: $parent, mode: ALL, locale: $locale) {
|
||||
id
|
||||
path
|
||||
title
|
||||
isFolder
|
||||
pageId
|
||||
parent
|
||||
locale
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
fetchPolicy: 'cache-first',
|
||||
variables: {
|
||||
parent: id,
|
||||
locale: this.locale
|
||||
}
|
||||
})
|
||||
return _.get(resp, 'data.pages.tree', [])
|
||||
},
|
||||
},
|
||||
mounted () {
|
||||
this.currentParent.title = `/ ${this.$t('common:sidebar.root')}`
|
||||
@ -227,12 +353,37 @@ export default {
|
||||
this.currentMode = 'browse'
|
||||
} else if (this.navMode === 'STATIC') {
|
||||
this.currentMode = 'custom'
|
||||
} else if (this.navMode === 'NEWTREE') {
|
||||
this.currentMode = 'tree'
|
||||
} else {
|
||||
this.currentMode = window.localStorage.getItem('navPref') || 'custom'
|
||||
}
|
||||
if (this.currentMode === 'browse') {
|
||||
this.loadFromCurrentPath()
|
||||
}
|
||||
if (this.currentMode === "tree") {
|
||||
this.fetchTreeRoot();
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
.v-treeview{
|
||||
.tree-item {
|
||||
font-weight: 500;
|
||||
line-height: 1rem;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
&.theme--dark{
|
||||
a {
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -75,6 +75,7 @@ type NavigationConfig {
|
||||
enum NavigationMode {
|
||||
NONE
|
||||
TREE
|
||||
NEWTREE
|
||||
MIXED
|
||||
STATIC
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user