Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wiki-js
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
1
Issues
1
List
Board
Labels
Milestones
Merge Requests
1
Merge Requests
1
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jacklull
wiki-js
Commits
3ca72ccc
Commit
3ca72ccc
authored
Feb 02, 2020
by
NGPixel
Committed by
Nicolas Giard
Apr 18, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: new nav UI (wip)
parent
53ceea74
Show whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
307 additions
and
83 deletions
+307
-83
admin-navigation.vue
client/components/admin/admin-navigation.vue
+178
-42
page-selector.vue
client/components/common/page-selector.vue
+1
-1
navigation-mutation-save-tree.gql
.../graph/admin/navigation/navigation-mutation-save-tree.gql
+0
-12
navigation-query-tree.gql
client/graph/admin/navigation/navigation-query-tree.gql
+0
-12
nav-sidebar.vue
client/themes/default/components/nav-sidebar.vue
+100
-9
navigation.js
server/graph/resolvers/navigation.js
+1
-1
navigation.graphql
server/graph/schemas/navigation.graphql
+12
-2
navigation.js
server/models/navigation.js
+15
-4
No files found.
client/components/admin/admin-navigation.vue
View file @
3ca72ccc
...
@@ -14,14 +14,65 @@
...
@@ -14,14 +14,65 @@
v-icon(left) mdi-check
v-icon(left) mdi-check
span
{{
$t
(
'common:actions.apply'
)
}}
span
{{
$t
(
'common:actions.apply'
)
}}
v-container.pa-0.mt-3(fluid, grid-list-lg)
v-container.pa-0.mt-3(fluid, grid-list-lg)
v-
layout(row
)
v-
row(dense
)
v-
flex(style='flex: 0 0 350px;
')
v-
col(cols='3
')
v-card.animated.fadeInUp
v-card.animated.fadeInUp
v-list.py-2(dense, nav, dark, :class='navTree.length < 1 ? "grey lighten-4" : "primary"')
v-toolbar(color='teal', dark, dense, flat, height='56')
v-toolbar-title.subtitle-1
{{
$t
(
'admin:navigation.mode'
)
}}
v-list(nav, two-line)
v-list-item-group(v-model='navMode', mandatory, :color='$vuetify.theme.dark ? `teal lighten-3` : `teal`')
v-list-item(value='classic')
v-list-item-avatar
img(src='/svg/icon-tree-structure-dotted.svg', alt='Site Tree')
v-list-item-content
v-list-item-title
{{
$t
(
'admin:navigation.modeSiteTree.title'
)
}}
v-list-item-subtitle
{{
$t
(
'admin:navigation.modeSiteTree.description'
)
}}
v-list-item-avatar
v-icon(v-if='$vuetify.theme.dark', :color='navMode === `classic` ? `teal lighten-3` : `grey darken-2`') mdi-check-circle
v-icon(v-else, :color='navMode === `classic` ? `teal` : `grey lighten-3`') mdi-check-circle
v-list-item(value='custom')
v-list-item-avatar
img(src='/svg/icon-user-menu-male-dotted.svg', alt='Custom Navigation')
v-list-item-content
v-list-item-title
{{
$t
(
'admin:navigation.modeCustom.title'
)
}}
v-list-item-subtitle
{{
$t
(
'admin:navigation.modeCustom.description'
)
}}
v-list-item-avatar
v-icon(v-if='$vuetify.theme.dark', :color='navMode === `custom` ? `teal lighten-3` : `grey darken-2`') mdi-check-circle
v-icon(v-else, :color='navMode === `custom` ? `teal` : `grey lighten-3`') mdi-check-circle
v-list-item(value='none')
v-list-item-avatar
img(src='/svg/icon-cancel-dotted.svg', alt='None')
v-list-item-content
v-list-item-title
{{
$t
(
'admin:navigation.modeNone.title'
)
}}
v-list-item-subtitle
{{
$t
(
'admin:navigation.modeNone.description'
)
}}
v-list-item-avatar
v-icon(v-if='$vuetify.theme.dark', :color='navMode === `none` ? `teal lighten-3` : `grey darken-2`') mdi-check-circle
v-icon(v-else, :color='navMode === `none` ? `teal` : `grey lighten-3`') mdi-check-circle
v-col(cols='9', v-if='navMode === `custom`')
v-card.animated.fadeInUp.wait-p2s
v-row(no-gutters, align='stretch')
v-col(style='flex: 0 0 350px;')
v-card.grey(flat, style='height: 100%; border-radius: 4px 0 0 4px;', :class='$vuetify.theme.dark ? `darken-4-l5` : `lighten-3`')
.teal.pa-2(style='margin-bottom: 1px; height: 56px;')
v-select(
v-if='locales.length > 0'
label='Locale'
hide-details
solo
flat
background-color='teal darken-2'
dark
dense
v-model='currentLang'
:items='locales'
item-text='name'
item-value='code'
)
v-list.py-2(dense, nav, dark, class='blue darken-2', style='border-radius: 0;')
v-list-item(v-if='navTree.length < 1')
v-list-item(v-if='navTree.length < 1')
v-list-item-avatar(size='24'): v-icon(color='grey') explore_off
v-list-item-avatar(size='24'): v-icon(color='blue lighten-3') mdi-alert
v-list-item-content
v-list-item-content
.caption.grey--text
{{
$t
(
'navigation.emptyList'
)
}}
em.caption.blue--text.text--lighten-4
{{
$t
(
'navigation.emptyList'
)
}}
draggable(v-model='navTree')
draggable(v-model='navTree')
template(v-for='navItem in navTree')
template(v-for='navItem in navTree')
v-list-item(
v-list-item(
...
@@ -61,9 +112,15 @@
...
@@ -61,9 +112,15 @@
v-list-item(@click='addItem("divider")')
v-list-item(@click='addItem("divider")')
v-list-item-avatar(size='24'): v-icon mdi-minus
v-list-item-avatar(size='24'): v-icon mdi-minus
v-list-item-title
{{
$t
(
'navigation.divider'
)
}}
v-list-item-title
{{
$t
(
'navigation.divider'
)
}}
v-flex.animated.fadeInUp.wait-p2s
v-col
v-card.wiki-form(v-if='current.kind === "link"')
v-card(flat, style='border-radius: 0 4px 4px 0;')
v-toolbar(dense, color='blue', flat, dark).subtitle-1
{{
$t
(
'navigation.edit'
,
{
kind
:
$t
(
'navigation.link'
)
}
)
}}
template(v-if='current.kind === "link"')
v-toolbar(height='56', color='teal lighten-1', flat, dark)
.subtitle-1
{{
$t
(
'navigation.edit'
,
{
kind
:
$t
(
'navigation.link'
)
}
)
}}
v
-
spacer
v
-
btn
.
px
-
5
(
color
=
'white'
,
outlined
,
@
click
=
'deleteItem(current)'
)
v
-
icon
(
left
)
mdi
-
delete
span
{{
$t
(
'navigation.delete'
,
{
kind
:
$t
(
'navigation.link'
)
}
)
}}
v
-
card
-
text
v
-
card
-
text
v
-
text
-
field
(
v
-
text
-
field
(
outlined
outlined
...
@@ -86,29 +143,33 @@
...
@@ -86,29 +143,33 @@
.
caption
.
pl
-
5
Refer
to
the
#
[
a
(
href
=
'https://fontawesome.com/icons?d=gallery&m=free'
,
target
=
'_blank'
)
Font
Awesome
5
Reference
]
for
the
list
of
all
possible
values
.
You
must
prefix
all
values
with
#
[
code
fas
fa
-
],
e
.
g
.
#
[
code
fas
fa
-
home
].
Note
that
some
icons
use
different
prefixes
(
e
.
g
.
#
[
code
fab
],
#
[
code
fad
],
#
[
code
fal
],
#
[
code
far
]).
.
caption
.
pl
-
5
Refer
to
the
#
[
a
(
href
=
'https://fontawesome.com/icons?d=gallery&m=free'
,
target
=
'_blank'
)
Font
Awesome
5
Reference
]
for
the
list
of
all
possible
values
.
You
must
prefix
all
values
with
#
[
code
fas
fa
-
],
e
.
g
.
#
[
code
fas
fa
-
home
].
Note
that
some
icons
use
different
prefixes
(
e
.
g
.
#
[
code
fab
],
#
[
code
fad
],
#
[
code
fal
],
#
[
code
far
]).
.
caption
.
pt
-
3
.
pl
-
5
:
strong
Font
Awesome
4
.
caption
.
pt
-
3
.
pl
-
5
:
strong
Font
Awesome
4
.
caption
.
pl
-
5
Refer
to
the
#
[
a
(
href
=
'https://fontawesome.com/v4.7.0/icons/'
,
target
=
'_blank'
)
Font
Awesome
4
Reference
]
for
the
list
of
all
possible
values
.
You
must
prefix
all
values
with
#
[
code
fa
fa
-
],
e
.
g
.
#
[
code
fa
fa
-
home
]
.
caption
.
pl
-
5
Refer
to
the
#
[
a
(
href
=
'https://fontawesome.com/v4.7.0/icons/'
,
target
=
'_blank'
)
Font
Awesome
4
Reference
]
for
the
list
of
all
possible
values
.
You
must
prefix
all
values
with
#
[
code
fa
fa
-
],
e
.
g
.
#
[
code
fa
fa
-
home
]
v
-
select
.
mt
-
4
(
v
-
divider
v
-
card
-
text
v
-
select
(
outlined
outlined
:
label
=
'$t("navigation.targetType")'
:
label
=
'$t("navigation.targetType")'
prepend
-
icon
=
'mdi-near-me'
prepend
-
icon
=
'mdi-near-me'
:
items
=
'navTypes'
:
items
=
'navTypes'
v
-
model
=
'current.targetType'
v
-
model
=
'current.targetType'
hide
-
details
)
)
v
-
text
-
field
(
v
-
text
-
field
.
mt
-
4
(
v
-
if
=
'current.targetType === `external`'
v
-
if
=
'current.targetType === `external`'
outlined
outlined
:
label
=
'$t("navigation.target")'
:
label
=
'$t("navigation.target")'
prepend
-
icon
=
'mdi-near-me'
prepend
-
icon
=
'mdi-near-me'
v
-
model
=
'current.target'
v
-
model
=
'current.target'
hide
-
details
)
)
v
-
btn
(
.
d
-
flex
.
align
-
center
.
mt
-
4
(
v
-
else
-
if
=
'current.targetType === "page"'
)
v
-
else
-
if
=
'current.targetType === "page"'
v
-
btn
.
ml
-
8
(
color
=
'indigo'
color
=
'primary'
:
dark
=
'false'
dark
disabled
@
click
=
'selectPage'
@
click
=
'selectPage'
)
)
v
-
icon
(
left
)
mdi
-
search
v
-
icon
(
left
)
mdi
-
magnify
span
Select
Page
...
span
{{
$t
(
'admin:navigation.selectPageButton'
)
}}
.
caption
.
ml
-
4
.
primary
--
text
{{
current
.
target
}}
v
-
text
-
field
(
v
-
text
-
field
(
v
-
else
-
if
=
'current.targetType === `search`'
v
-
else
-
if
=
'current.targetType === `search`'
outlined
outlined
...
@@ -116,15 +177,15 @@
...
@@ -116,15 +177,15 @@
prepend
-
icon
=
'search'
prepend
-
icon
=
'search'
v
-
model
=
'current.target'
v
-
model
=
'current.target'
)
)
v
-
divider
v
-
card
-
chin
template
(
v
-
else
-
if
=
'current.kind === "header"'
)
v
-
toolbar
(
height
=
'56'
,
color
=
'teal lighten-1'
,
flat
,
dark
)
.
subtitle
-
1
{{
$t
(
'navigation.edit'
,
{
kind
:
$t
(
'navigation.header'
)
}
)
}}
v
-
spacer
v
-
spacer
v
-
btn
.
px
-
5
(
color
=
'red
'
,
outlined
,
@
click
=
'deleteItem(current)'
)
v
-
btn
.
px
-
5
(
color
=
'white
'
,
outlined
,
@
click
=
'deleteItem(current)'
)
v
-
icon
(
left
)
mdi
-
delete
v
-
icon
(
left
)
mdi
-
delete
span
{{
$t
(
'navigation.delete'
,
{
kind
:
$t
(
'navigation.link'
)
}
)
}}
span
{{
$t
(
'navigation.delete'
,
{
kind
:
$t
(
'navigation.header'
)
}
)
}}
v
-
card
(
v
-
else
-
if
=
'current.kind === "header"'
)
v
-
toolbar
(
dense
,
color
=
'blue'
,
flat
,
dark
)
.
subtitle
-
1
{{
$t
(
'navigation.edit'
,
{
kind
:
$t
(
'navigation.header'
)
}
)
}}
v
-
card
-
text
v
-
card
-
text
v
-
text
-
field
(
v
-
text
-
field
(
outlined
outlined
...
@@ -132,55 +193,87 @@
...
@@ -132,55 +193,87 @@
prepend
-
icon
=
'mdi-format-title'
prepend
-
icon
=
'mdi-format-title'
v
-
model
=
'current.label'
v
-
model
=
'current.label'
)
)
v
-
card
-
chin
v
-
divider
v
-
spacer
v
-
btn
.
px
-
5
(
color
=
'red'
,
outlined
,
@
click
=
'deleteItem(current)'
)
v
-
icon
(
left
)
mdi
-
delete
span
{{
$t
(
'navigation.delete'
,
{
kind
:
$t
(
'navigation.header'
)
}
)
}}
div
(
v
-
else
-
if
=
'current.kind === "divider"'
)
div
(
v
-
else
-
if
=
'current.kind === "divider"'
)
v
-
btn
.
mt
-
0
.
px
-
5
(
color
=
'red'
,
outlined
,
@
click
=
'deleteItem(current)'
)
v
-
toolbar
(
height
=
'56'
,
color
=
'teal lighten-1'
,
flat
,
dark
)
.
subtitle
-
1
{{
$t
(
'navigation.edit'
,
{
kind
:
$t
(
'navigation.divider'
)
}
)
}}
v
-
spacer
v
-
btn
.
px
-
5
(
color
=
'white'
,
outlined
,
@
click
=
'deleteItem(current)'
)
v
-
icon
(
left
)
mdi
-
delete
v
-
icon
(
left
)
mdi
-
delete
span
{{
$t
(
'navigation.delete'
,
{
kind
:
$t
(
'navigation.divider'
)
}
)
}}
span
{{
$t
(
'navigation.delete'
,
{
kind
:
$t
(
'navigation.divider'
)
}
)
}}
v
-
card
(
v
-
else
)
v
-
card
-
text
(
v
-
if
=
'current.kind'
)
v
-
radio
-
group
.
pl
-
8
(
v
-
model
=
'current.visibilityMode'
,
mandatory
,
hide
-
details
)
v
-
radio
(:
label
=
'$t("admin:navigation.visibilityMode.all")'
,
value
=
'all'
,
color
=
'primary'
)
v
-
radio
.
mt
-
3
(:
label
=
'$t("admin:navigation.visibilityMode.restricted")'
,
value
=
'restricted'
,
color
=
'primary'
)
.
pl
-
8
v
-
select
.
pl
-
8
.
mt
-
3
(
item
-
text
=
'name'
item
-
value
=
'id'
outlined
prepend
-
icon
=
'mdi-account-group'
label
=
'Groups'
:
disabled
=
'current.visibilityMode !== `restricted`'
v
-
model
=
'current.visibilityGroups'
:
items
=
'groups'
persistent
-
hint
clearable
multiple
)
template
(
v
-
else
)
v
-
toolbar
(
height
=
'56'
,
color
=
'teal lighten-1'
,
flat
,
dark
)
v
-
card
-
text
.
grey
--
text
(
v
-
if
=
'navTree.length > 0'
)
{{
$t
(
'navigation.noSelectionText'
)
}}
v
-
card
-
text
.
grey
--
text
(
v
-
if
=
'navTree.length > 0'
)
{{
$t
(
'navigation.noSelectionText'
)
}}
v
-
card
-
text
.
grey
--
text
(
v
-
else
)
{{
$t
(
'navigation.noItemsText'
)
}}
v
-
card
-
text
.
grey
--
text
(
v
-
else
)
{{
$t
(
'navigation.noItemsText'
)
}}
page
-
selector
(
mode
=
'select'
,
v
-
model
=
'selectPageModal'
,
:
open
-
handler
=
'selectPageHandle'
,
path
=
'home'
,
:
locale
=
'currentLang'
)
<
/template
>
<
/template
>
<
script
>
<
script
>
import
_
from
'lodash'
import
_
from
'lodash'
import
{
v4
as
uuid
}
from
'uuid'
import
gql
from
'graphql-tag'
import
uuid
from
'uuid/v4'
import
treeSaveMutation
from
'gql/admin/navigation/navigation-mutation-save-tree.gql'
import
groupsQuery
from
'gql/admin/users/users-query-groups.gql'
import
treeQuery
from
'gql/admin/navigation/navigation-query-tree.gql'
import
draggable
from
'vuedraggable'
import
draggable
from
'vuedraggable'
/* global siteConfig, siteLangs */
export
default
{
export
default
{
components
:
{
components
:
{
draggable
draggable
}
,
}
,
data
()
{
data
()
{
return
{
return
{
selectPageModal
:
false
,
navMode
:
'custom'
,
navTree
:
[],
navTree
:
[],
current
:
{
}
current
:
{
}
,
currentLang
:
'en'
,
groups
:
[]
}
}
}
,
}
,
computed
:
{
computed
:
{
navTypes
()
{
navTypes
()
{
return
[
return
[
//
{
text
:
this
.
$t
(
'navigation.navType.external'
),
value
:
'external'
}
,
{
text
:
this
.
$t
(
'navigation.navType.external'
),
value
:
'external'
}
,
{
text
:
this
.
$t
(
'navigation.navType.home'
),
value
:
'home'
}
,
{
text
:
this
.
$t
(
'navigation.navType.home'
),
value
:
'home'
}
,
{
text
:
'Internal Path / External Link'
,
value
:
'external'
}
{
text
:
this
.
$t
(
'navigation.navType.page'
),
value
:
'page'
}
//
{
text
:
this
.
$t
(
'navigation.navType.page'
),
value
:
'page'
}
//
{
text
:
this
.
$t
(
'navigation.navType.searchQuery'
),
value
:
'search'
}
//
{
text
:
this
.
$t
(
'navigation.navType.searchQuery'
),
value
:
'search'
}
]
]
}
,
locales
()
{
return
siteLangs
}
}
}
,
}
,
methods
:
{
methods
:
{
addItem
(
kind
)
{
addItem
(
kind
)
{
let
newItem
=
{
let
newItem
=
{
id
:
uuid
(),
id
:
uuid
(),
kind
kind
,
visibilityMode
:
'all'
,
visibilityGroups
:
[]
}
}
switch
(
kind
)
{
switch
(
kind
)
{
case
'link'
:
case
'link'
:
...
@@ -207,13 +300,29 @@ export default {
...
@@ -207,13 +300,29 @@ export default {
this
.
current
=
item
this
.
current
=
item
}
,
}
,
selectPage
()
{
selectPage
()
{
window
.
alert
(
`Coming soon. Use External Link for now (you can still specify internal links).`
)
this
.
selectPageModal
=
true
}
,
selectPageHandle
({
path
,
locale
}
)
{
this
.
current
.
target
=
`/${locale
}
/${path
}
`
}
,
}
,
async
save
()
{
async
save
()
{
this
.
$store
.
commit
(
`loadingStart`
,
'admin-navigation-save'
)
this
.
$store
.
commit
(
`loadingStart`
,
'admin-navigation-save'
)
try
{
try
{
const
resp
=
await
this
.
$apollo
.
mutate
({
const
resp
=
await
this
.
$apollo
.
mutate
({
mutation
:
treeSaveMutation
,
mutation
:
gql
`
mutation ($tree: [NavigationTreeInput]!) {
navigation{
updateTree(tree: $tree) {
responseResult {
succeeded
errorCode
slug
message
}
}
}
}
`
,
variables
:
{
variables
:
{
tree
:
this
.
navTree
tree
:
this
.
navTree
}
}
...
@@ -242,14 +351,41 @@ export default {
...
@@ -242,14 +351,41 @@ export default {
}
)
}
)
}
}
}
,
}
,
mounted
()
{
this
.
currentLang
=
siteConfig
.
lang
}
,
apollo
:
{
apollo
:
{
navTree
:
{
navTree
:
{
query
:
treeQuery
,
query
:
gql
`
{
navigation {
tree {
locale
items {
id
kind
label
icon
targetType
target
}
}
}
}
`
,
fetchPolicy
:
'network-only'
,
fetchPolicy
:
'network-only'
,
update
:
(
data
)
=>
_
.
cloneDeep
(
data
.
navigation
.
tree
),
update
:
(
data
)
=>
_
.
cloneDeep
(
data
.
navigation
.
tree
),
watchLoading
(
isLoading
)
{
watchLoading
(
isLoading
)
{
this
.
$store
.
commit
(
`loading${isLoading ? 'Start' : 'Stop'
}
`
,
'admin-navigation-tree'
)
this
.
$store
.
commit
(
`loading${isLoading ? 'Start' : 'Stop'
}
`
,
'admin-navigation-tree'
)
}
}
}
,
groups
:
{
query
:
groupsQuery
,
fetchPolicy
:
'network-only'
,
update
:
(
data
)
=>
data
.
groups
.
list
,
watchLoading
(
isLoading
)
{
this
.
$store
.
commit
(
`loading${isLoading ? 'Start' : 'Stop'
}
`
,
'admin-navigation-groups'
)
}
}
}
}
}
}
}
...
...
client/components/common/page-selector.vue
View file @
3ca72ccc
...
@@ -10,7 +10,7 @@
...
@@ -10,7 +10,7 @@
v-icon.mr-3(color='white') mdi-page-next-outline
v-icon.mr-3(color='white') mdi-page-next-outline
.body-1(v-if='mode === `create`') Select New Page Location
.body-1(v-if='mode === `create`') Select New Page Location
.body-1(v-else-if='mode === `move`') Move / Rename Page Location
.body-1(v-else-if='mode === `move`') Move / Rename Page Location
.body-1(v-else-if='mode === `select`') Select Page
.body-1(v-else-if='mode === `select`') Select
a
Page
v-spacer
v-spacer
v-progress-circular(
v-progress-circular(
indeterminate
indeterminate
...
...
client/graph/admin/navigation/navigation-mutation-save-tree.gql
deleted
100644 → 0
View file @
53ceea74
mutation
(
$tree
:
[
NavigationItemInput
]!)
{
navigation
{
updateTree
(
tree
:
$tree
)
{
responseResult
{
succeeded
errorCode
slug
message
}
}
}
}
client/graph/admin/navigation/navigation-query-tree.gql
deleted
100644 → 0
View file @
53ceea74
{
navigation
{
tree
{
id
kind
label
icon
targetType
target
}
}
}
client/themes/default/components/nav-sidebar.vue
View file @
3ca72ccc
<
template
lang=
"pug"
>
<
template
lang=
"pug"
>
div
div
//- .blue.darken-3.pa-3.d-flex
.blue.darken-3.pa-3.d-flex
//- v-btn(depressed, color='blue darken-2', style='min-width:0;', href='/')
v-btn(depressed, color='blue darken-2', style='min-width:0;', href='/')
//- v-icon(size='20') mdi-home
v-icon(size='20') mdi-home
//- v-btn.ml-3(depressed, color='blue darken-2', style='flex: 1 1 100%;')
v-btn.ml-3(v-if='currentMode === `custom`', depressed, color='blue darken-2', style='flex: 1 1 100%;', @click='switchMode(`browse`)')
//- v-icon(left) mdi-file-tree
v-icon(left) mdi-file-tree
//- .body-2.text-none Browse
.body-2.text-none Browse
//- v-divider
v-btn.ml-3(v-else-if='currentMode === `browse`', depressed, color='blue darken-2', style='flex: 1 1 100%;', @click='switchMode(`custom`)')
v-list.py-2(dense, :class='color', :dark='dark')
v-icon(left) mdi-navigation
.body-2.text-none Main Menu
v-divider
//-> Custom Navigation
v-list.py-2(v-if='currentMode === `custom`', dense, :class='color', :dark='dark')
template(v-for='item of items')
template(v-for='item of items')
v-list-item(
v-list-item(
v-if='item.kind === `link`'
v-if='item.kind === `link`'
...
@@ -18,9 +22,31 @@
...
@@ -18,9 +22,31 @@
v-list-item-title
{{
item
.
label
}}
v-list-item-title
{{
item
.
label
}}
v-divider.my-2(v-else-if='item.kind === `divider`')
v-divider.my-2(v-else-if='item.kind === `divider`')
v-subheader.pl-4(v-else-if='item.kind === `header`')
{{
item
.
label
}}
v-subheader.pl-4(v-else-if='item.kind === `header`')
{{
item
.
label
}}
//-> Browse
v-list.py-2(v-else-if='currentMode === `browse`', dense, :class='color', :dark='dark')
template(v-if='currentParent.id > 0')
v-list-item(v-for='(item, idx) of parents', :key='`parent-` + item.id', @click='fetchBrowseItems(item)', style='min-height: 30px;')
v-list-item-avatar(size='18', :style='`padding-left: ` + (idx * 8) + `px; width: auto; margin: 0 5px 0 0;`')
v-icon(small) mdi-folder-open
v-list-item-title
{{
item
.
title
}}
v-divider.mt-2
v-subheader.pl-4 Current Directory
template(v-for='item of currentItems')
v-list-item(v-if='item.isFolder', :key='`childfolder-` + item.id', @click='fetchBrowseItems(item)')
v-list-item-avatar(size='24')
v-icon mdi-folder
v-list-item-title
{{
item
.
title
}}
v-list-item(v-else, :href='`/` + item.path', :key='`childpage-` + item.id', :input-value='path === item.path')
v-list-item-avatar(size='24')
v-icon mdi-file-document-box
v-list-item-title
{{
item
.
title
}}
</
template
>
</
template
>
<
script
>
<
script
>
import
_
from
'lodash'
import
gql
from
'graphql-tag'
import
{
get
}
from
'vuex-pathify'
export
default
{
export
default
{
props
:
{
props
:
{
color
:
{
color
:
{
...
@@ -34,10 +60,75 @@ export default {
...
@@ -34,10 +60,75 @@ export default {
items
:
{
items
:
{
type
:
Array
,
type
:
Array
,
default
:
()
=>
[]
default
:
()
=>
[]
},
mode
:
{
type
:
String
,
default
:
'browse'
}
}
},
},
data
()
{
data
()
{
return
{}
return
{
currentMode
:
'browse'
,
currentItems
:
[],
currentParent
:
{
id
:
0
,
title
:
'/ (root)'
},
all
:
[]
}
},
computed
:
{
path
:
get
(
'page/path'
),
locale
:
get
(
'page/locale'
)
},
methods
:
{
switchMode
(
mode
)
{
this
.
currentMode
=
mode
if
(
mode
===
`browse`
)
{
this
.
fetchBrowseItems
()
}
},
async
fetchBrowseItems
(
item
)
{
this
.
$store
.
commit
(
`loadingStart`
,
'browse-load'
)
if
(
!
item
)
{
item
=
this
.
currentParent
}
else
{
if
(
!
_
.
some
(
this
.
parents
,
[
'id'
,
item
.
id
]))
{
this
.
parents
.
push
(
this
.
currentParent
)
}
this
.
currentParent
=
item
}
const
resp
=
await
this
.
$apollo
.
query
({
query
:
gql
`
query ($parent: Int!, $locale: String!) {
pages {
tree(parent: $parent, mode: ALL, locale: $locale, includeParents: true) {
id
path
title
isFolder
pageId
parent
}
}
}
`
,
fetchPolicy
:
'cache-first'
,
variables
:
{
parent
:
item
.
id
,
locale
:
this
.
locale
}
})
this
.
currentItems
=
_
.
get
(
resp
,
'data.pages.tree'
,
[])
this
.
all
.
push
(...
this
.
currentItems
)
this
.
$store
.
commit
(
`loadingStop`
,
'browse-load'
)
}
},
mounted
()
{
this
.
currentMode
=
this
.
mode
if
(
this
.
mode
===
'browse'
)
{
this
.
fetchBrowseItems
()
}
}
}
}
}
</
script
>
</
script
>
server/graph/resolvers/navigation.js
View file @
3ca72ccc
...
@@ -11,7 +11,7 @@ module.exports = {
...
@@ -11,7 +11,7 @@ module.exports = {
},
},
NavigationQuery
:
{
NavigationQuery
:
{
async
tree
(
obj
,
args
,
context
,
info
)
{
async
tree
(
obj
,
args
,
context
,
info
)
{
return
WIKI
.
models
.
navigation
.
getTree
()
return
WIKI
.
models
.
navigation
.
getTree
(
{
cache
:
false
,
locale
:
'all'
}
)
}
}
},
},
NavigationMutation
:
{
NavigationMutation
:
{
...
...
server/graph/schemas/navigation.graphql
View file @
3ca72ccc
...
@@ -15,7 +15,7 @@ extend type Mutation {
...
@@ -15,7 +15,7 @@ extend type Mutation {
# -----------------------------------------------
# -----------------------------------------------
type
NavigationQuery
{
type
NavigationQuery
{
tree
:
[
Navigation
Item
]!
tree
:
[
Navigation
Tree
]!
}
}
# -----------------------------------------------
# -----------------------------------------------
...
@@ -24,7 +24,7 @@ type NavigationQuery {
...
@@ -24,7 +24,7 @@ type NavigationQuery {
type
NavigationMutation
{
type
NavigationMutation
{
updateTree
(
updateTree
(
tree
:
[
Navigation
Item
Input
]!
tree
:
[
Navigation
Tree
Input
]!
):
DefaultResponse
@
auth
(
requires
:
[
"
manage
:
navigation
"
,
"
manage
:
system
"
])
):
DefaultResponse
@
auth
(
requires
:
[
"
manage
:
navigation
"
,
"
manage
:
system
"
])
}
}
...
@@ -32,6 +32,16 @@ type NavigationMutation {
...
@@ -32,6 +32,16 @@ type NavigationMutation {
# TYPES
# TYPES
# -----------------------------------------------
# -----------------------------------------------
type
NavigationTree
{
locale
:
String
!
items
:
[
NavigationItem
]!
}
input
NavigationTreeInput
{
locale
:
String
!
items
:
[
NavigationItemInput
]!
}
type
NavigationItem
{
type
NavigationItem
{
id
:
String
!
id
:
String
!
kind
:
String
!
kind
:
String
!
...
...
server/models/navigation.js
View file @
3ca72ccc
const
Model
=
require
(
'objection'
).
Model
const
Model
=
require
(
'objection'
).
Model
const
_
=
require
(
'lodash'
)
/* global WIKI */
/* global WIKI */
...
@@ -21,19 +22,29 @@ module.exports = class Navigation extends Model {
...
@@ -21,19 +22,29 @@ module.exports = class Navigation extends Model {
}
}
}
}
static
async
getTree
({
cache
=
false
}
=
{})
{
static
async
getTree
({
cache
=
false
,
locale
=
'en'
}
=
{})
{
if
(
cache
)
{
if
(
cache
)
{
const
navTreeCached
=
await
WIKI
.
cache
.
get
(
'nav:sidebar'
)
const
navTreeCached
=
await
WIKI
.
cache
.
get
(
`nav:sidebar:
${
locale
}
`
)
if
(
navTreeCached
)
{
if
(
navTreeCached
)
{
return
navTreeCached
return
navTreeCached
}
}
}
}
const
navTree
=
await
WIKI
.
models
.
navigation
.
query
().
findOne
(
'key'
,
'site'
)
const
navTree
=
await
WIKI
.
models
.
navigation
.
query
().
findOne
(
'key'
,
'site'
)
if
(
navTree
)
{
if
(
navTree
)
{
// Check for pre-2.1 format
if
(
_
.
has
(
navTree
.
config
[
0
],
'kind'
))
{
navTree
.
config
=
[{
locale
:
'en'
,
items
:
navTree
.
config
}]
}
for
(
const
tree
of
navTree
.
config
)
{
if
(
cache
)
{
if
(
cache
)
{
await
WIKI
.
cache
.
set
(
'nav:sidebar'
,
navTree
.
config
,
300
)
await
WIKI
.
cache
.
set
(
`nav:sidebar:
${
tree
.
locale
}
`
,
tree
.
items
,
300
)
}
}
}
return
navTree
.
config
return
locale
===
'all'
?
navTree
.
config
:
WIKI
.
cache
.
get
(
`nav:sidebar:
${
locale
}
`
)
}
else
{
}
else
{
WIKI
.
logger
.
warn
(
'Site Navigation is missing or corrupted.'
)
WIKI
.
logger
.
warn
(
'Site Navigation is missing or corrupted.'
)
return
[]
return
[]
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment