Skip to content

Commit edd0c1a

Browse files
committed
feat: admin navigation UI
1 parent ca9ab47 commit edd0c1a

File tree

5 files changed

+214
-20
lines changed

5 files changed

+214
-20
lines changed

client/app.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,8 @@ Vue.component('admin', () => import(/* webpackChunkName: "admin" */ './component
113113
Vue.component('editor', () => import(/* webpackPrefetch: -100, webpackChunkName: "editor" */ './components/editor.vue'))
114114
Vue.component('login', () => import(/* webpackPrefetch: true, webpackChunkName: "login" */ './components/login.vue'))
115115
Vue.component('nav-footer', () => import(/* webpackMode: "eager" */ './components/common/nav-footer.vue'))
116-
Vue.component('nav-header', () => import(/* webpackMode: "lazy" */ './components/common/nav-header.vue'))
116+
Vue.component('nav-header', () => import(/* webpackMode: "eager" */ './components/common/nav-header.vue'))
117+
Vue.component('nav-sidebar', () => import(/* webpackMode: "eager" */ './components/common/nav-sidebar.vue'))
117118
Vue.component('profile', () => import(/* webpackChunkName: "profile" */ './components/profile.vue'))
118119
Vue.component('setup', () => import(/* webpackChunkName: "setup" */ './components/setup.vue'))
119120
Vue.component('v-card-chin', () => import(/* webpackPrefetch: true, webpackChunkName: "ui-extra" */ './components/common/v-card-chin.vue'))

client/components/admin.vue

+4-4
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,12 @@
1414
v-list-tile(to='/locale')
1515
v-list-tile-avatar: v-icon language
1616
v-list-tile-title {{ $t('admin:locale.title') }}
17+
v-list-tile(to='/navigation')
18+
v-list-tile-avatar: v-icon near_me
19+
v-list-tile-title {{ $t('admin:navigation.title') }}
1720
v-list-tile(to='/pages')
1821
v-list-tile-avatar: v-icon insert_drive_file
1922
v-list-tile-title {{ $t('admin:pages.title') }}
20-
v-list-tile(to='/stats')
21-
v-list-tile-avatar: v-icon show_chart
22-
v-list-tile-title {{ $t('admin:stats.title') }}
2323
v-list-tile(to='/theme')
2424
v-list-tile-avatar: v-icon palette
2525
v-list-tile-title {{ $t('admin:theme.title') }}
@@ -93,8 +93,8 @@ const router = new VueRouter({
9393
{ path: '/dashboard', component: () => import(/* webpackChunkName: "admin" */ './admin/admin-dashboard.vue') },
9494
{ path: '/general', component: () => import(/* webpackChunkName: "admin" */ './admin/admin-general.vue') },
9595
{ path: '/locale', component: () => import(/* webpackChunkName: "admin" */ './admin/admin-locale.vue') },
96+
{ path: '/navigation', component: () => import(/* webpackChunkName: "admin" */ './admin/admin-navigation.vue') },
9697
{ path: '/pages', component: () => import(/* webpackChunkName: "admin" */ './admin/admin-pages.vue') },
97-
{ path: '/stats', component: () => import(/* webpackChunkName: "admin" */ './admin/admin-stats.vue') },
9898
{ path: '/theme', component: () => import(/* webpackChunkName: "admin" */ './admin/admin-theme.vue') },
9999
{ path: '/groups', component: () => import(/* webpackChunkName: "admin" */ './admin/admin-groups.vue') },
100100
{ path: '/groups/:id', component: () => import(/* webpackChunkName: "admin" */ './admin/admin-groups-edit.vue') },
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
<template lang='pug'>
2+
v-container(fluid, fill-height)
3+
v-layout(row wrap)
4+
v-flex(xs12)
5+
.admin-header-icon: v-icon(size='80', color='grey lighten-2') near_me
6+
.headline.primary--text {{$t('admin:navigation.title')}}
7+
.subheading.grey--text {{$t('admin:navigation.subtitle')}}
8+
v-container.pa-0.mt-3(fluid, grid-list-lg)
9+
v-layout(row)
10+
v-flex(style='flex: 0 0 350px;')
11+
v-card
12+
v-list.primary.py-2(dense, dark)
13+
draggable
14+
template(v-for='navItem in navTree')
15+
v-list-tile(v-if='navItem.kind === "link"', :class='(navItem === current) ? "blue" : ""', @click='selectItem(navItem)')
16+
v-list-tile-avatar: v-icon {{navItem.icon}}
17+
v-list-tile-title {{navItem.label}}
18+
.py-2.clickable(v-else-if='navItem.kind === "divider"', :class='(navItem === current) ? "blue" : ""', @click='selectItem(navItem)')
19+
v-divider
20+
v-subheader.pl-4.clickable(v-else-if='navItem.kind === "header"', :class='(navItem === current) ? "blue" : ""', @click='selectItem(navItem)') {{navItem.label}}
21+
v-card-chin
22+
v-spacer
23+
v-menu(offset-y, bottom, min-width='200px')
24+
v-btn(slot='activator', color='primary', depressed)
25+
v-icon(left) add
26+
span Add
27+
v-list
28+
v-list-tile(@click='addItem("link")')
29+
v-list-tile-avatar: v-icon link
30+
v-list-tile-title Link
31+
v-list-tile(@click='addItem("header")')
32+
v-list-tile-avatar: v-icon title
33+
v-list-tile-title Header
34+
v-list-tile(@click='addItem("divider")')
35+
v-list-tile-avatar: v-icon power_input
36+
v-list-tile-title Divider
37+
v-btn.ml-2(color='success', depressed)
38+
v-icon(left) check
39+
span Save
40+
v-flex
41+
v-card(v-if='current.kind === "link"')
42+
v-toolbar(dense, color='blue', flat, dark)
43+
.subheading Edit Link
44+
v-card-text
45+
v-text-field(
46+
outline
47+
background-color='grey lighten-2'
48+
label='Label'
49+
prepend-icon='title'
50+
v-model='current.label'
51+
)
52+
v-text-field(
53+
outline
54+
background-color='grey lighten-2'
55+
label='Icon'
56+
prepend-icon='casino'
57+
v-model='current.icon'
58+
)
59+
v-select(
60+
outline
61+
background-color='grey lighten-2'
62+
label='Target Type'
63+
prepend-icon='near_me'
64+
:items='navTypes'
65+
v-model='current.targetType'
66+
)
67+
v-text-field(
68+
v-if='current.targetType === "external"'
69+
outline
70+
background-color='grey lighten-2'
71+
label='Target'
72+
prepend-icon='near_me'
73+
v-model='current.target'
74+
)
75+
v-card-chin
76+
v-spacer
77+
v-btn(color='red', outline)
78+
v-icon(left) delete
79+
span Delete Link
80+
v-card(v-else-if='current.kind === "header"')
81+
v-toolbar(dense, color='blue', flat, dark)
82+
.subheading Edit Header
83+
v-card-text
84+
v-text-field(
85+
outline
86+
background-color='grey lighten-2'
87+
label='Label'
88+
prepend-icon='title'
89+
v-model='current.label'
90+
)
91+
v-card-chin
92+
v-spacer
93+
v-btn(color='red', outline)
94+
v-icon(left) delete
95+
span Delete Header
96+
div(v-else-if='current.kind === "divider"')
97+
v-btn.mt-0(color='red', outline)
98+
v-icon(left) delete
99+
span Delete Divider
100+
v-card(v-else)
101+
v-card-text.grey--text Select a navigation item on the left.
102+
103+
</template>
104+
105+
<script>
106+
import draggable from 'vuedraggable'
107+
108+
export default {
109+
components: {
110+
draggable
111+
},
112+
data() {
113+
return {
114+
navTypes: [
115+
{ text: 'External Link', value: 'external' },
116+
{ text: 'Home', value: 'home' },
117+
{ text: 'Page', value: 'page' },
118+
{ text: 'Search Query', value: 'search' }
119+
],
120+
navTree: [
121+
{
122+
kind: 'link',
123+
label: 'Home',
124+
icon: 'home',
125+
targetType: 'home',
126+
target: '/'
127+
}
128+
],
129+
current: {}
130+
}
131+
},
132+
methods: {
133+
addItem(kind) {
134+
let newItem = {
135+
kind
136+
}
137+
switch (kind) {
138+
case 'link':
139+
newItem = {
140+
...newItem,
141+
label: 'Untitled Link',
142+
icon: 'chevron_right',
143+
targetType: 'home',
144+
target: '/'
145+
}
146+
break
147+
case 'header':
148+
newItem.label = 'Untitled Header'
149+
break
150+
}
151+
this.navTree.push(newItem)
152+
this.current = newItem
153+
},
154+
selectItem(item) {
155+
this.current = item
156+
}
157+
}
158+
}
159+
</script>
160+
161+
<style lang='scss' scoped>
162+
163+
.clickable {
164+
cursor: pointer;
165+
166+
&:hover {
167+
background-color: rgba(mc('blue', '500'), .25);
168+
}
169+
}
170+
171+
</style>
+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<template lang="pug">
2+
v-list(dense, :class='color', :dark='dark')
3+
v-list-tile.pt-2(href='/')
4+
v-list-tile-avatar: v-icon home
5+
v-list-tile-title Home
6+
v-divider.my-2
7+
v-subheader.pl-4 Navigation
8+
v-list-tile
9+
v-list-tile-avatar: v-icon stars
10+
v-list-tile-title The Universe
11+
v-list-tile
12+
v-list-tile-avatar: v-icon directions_boat
13+
v-list-tile-title Ships
14+
v-list-tile
15+
v-list-tile-avatar: v-icon local_airport
16+
v-list-tile-title Airports
17+
</template>
18+
19+
<script>
20+
export default {
21+
props: {
22+
color: {
23+
type: String,
24+
default: 'primary'
25+
},
26+
dark: {
27+
type: Boolean,
28+
default: true
29+
}
30+
},
31+
data() {
32+
return {}
33+
}
34+
}
35+
</script>

client/themes/default/components/app.vue

+2-15
Original file line numberDiff line numberDiff line change
@@ -11,28 +11,15 @@
1111
:temporary='$vuetify.breakpoint.xs'
1212
v-model='navShown'
1313
)
14-
v-list(dense)
15-
v-list-tile.pt-2(href='/')
16-
v-list-tile-avatar: v-icon home
17-
v-list-tile-title Home
18-
v-divider.my-2
19-
v-subheader.pl-4 Navigation
20-
v-list-tile
21-
v-list-tile-avatar: v-icon stars
22-
v-list-tile-title The Universe
23-
v-list-tile
24-
v-list-tile-avatar: v-icon directions_boat
25-
v-list-tile-title Ships
26-
v-list-tile
27-
v-list-tile-avatar: v-icon local_airport
28-
v-list-tile-title Airports
14+
nav-sidebar
2915

3016
v-content
3117
v-toolbar(color='grey lighten-3', flat, dense)
3218
v-btn.pl-0(v-if='$vuetify.breakpoint.xsOnly', flat, @click='toggleNavigation')
3319
v-icon(color='grey darken-2', left) menu
3420
span Navigation
3521
v-breadcrumbs.pl-0(v-else, divider='/')
22+
v-breadcrumbs-item: v-icon home
3623
v-breadcrumbs-item Universe
3724
v-breadcrumbs-item Galaxy
3825
v-breadcrumbs-item Solar System

0 commit comments

Comments
 (0)