feat: admin navigation UI
This commit is contained in:
		| @@ -113,7 +113,8 @@ Vue.component('admin', () => import(/* webpackChunkName: "admin" */ './component | |||||||
| Vue.component('editor', () => import(/* webpackPrefetch: -100, webpackChunkName: "editor" */ './components/editor.vue')) | Vue.component('editor', () => import(/* webpackPrefetch: -100, webpackChunkName: "editor" */ './components/editor.vue')) | ||||||
| Vue.component('login', () => import(/* webpackPrefetch: true, webpackChunkName: "login" */ './components/login.vue')) | Vue.component('login', () => import(/* webpackPrefetch: true, webpackChunkName: "login" */ './components/login.vue')) | ||||||
| Vue.component('nav-footer', () => import(/* webpackMode: "eager" */ './components/common/nav-footer.vue')) | Vue.component('nav-footer', () => import(/* webpackMode: "eager" */ './components/common/nav-footer.vue')) | ||||||
| Vue.component('nav-header', () => import(/* webpackMode: "lazy" */ './components/common/nav-header.vue')) | Vue.component('nav-header', () => import(/* webpackMode: "eager" */ './components/common/nav-header.vue')) | ||||||
|  | Vue.component('nav-sidebar', () => import(/* webpackMode: "eager" */ './components/common/nav-sidebar.vue')) | ||||||
| Vue.component('profile', () => import(/* webpackChunkName: "profile" */ './components/profile.vue')) | Vue.component('profile', () => import(/* webpackChunkName: "profile" */ './components/profile.vue')) | ||||||
| Vue.component('setup', () => import(/* webpackChunkName: "setup" */ './components/setup.vue')) | Vue.component('setup', () => import(/* webpackChunkName: "setup" */ './components/setup.vue')) | ||||||
| Vue.component('v-card-chin', () => import(/* webpackPrefetch: true, webpackChunkName: "ui-extra" */ './components/common/v-card-chin.vue')) | Vue.component('v-card-chin', () => import(/* webpackPrefetch: true, webpackChunkName: "ui-extra" */ './components/common/v-card-chin.vue')) | ||||||
|   | |||||||
| @@ -14,12 +14,12 @@ | |||||||
|         v-list-tile(to='/locale') |         v-list-tile(to='/locale') | ||||||
|           v-list-tile-avatar: v-icon language |           v-list-tile-avatar: v-icon language | ||||||
|           v-list-tile-title {{ $t('admin:locale.title') }} |           v-list-tile-title {{ $t('admin:locale.title') }} | ||||||
|  |         v-list-tile(to='/navigation') | ||||||
|  |           v-list-tile-avatar: v-icon near_me | ||||||
|  |           v-list-tile-title {{ $t('admin:navigation.title') }} | ||||||
|         v-list-tile(to='/pages') |         v-list-tile(to='/pages') | ||||||
|           v-list-tile-avatar: v-icon insert_drive_file |           v-list-tile-avatar: v-icon insert_drive_file | ||||||
|           v-list-tile-title {{ $t('admin:pages.title') }} |           v-list-tile-title {{ $t('admin:pages.title') }} | ||||||
|         v-list-tile(to='/stats') |  | ||||||
|           v-list-tile-avatar: v-icon show_chart |  | ||||||
|           v-list-tile-title {{ $t('admin:stats.title') }} |  | ||||||
|         v-list-tile(to='/theme') |         v-list-tile(to='/theme') | ||||||
|           v-list-tile-avatar: v-icon palette |           v-list-tile-avatar: v-icon palette | ||||||
|           v-list-tile-title {{ $t('admin:theme.title') }} |           v-list-tile-title {{ $t('admin:theme.title') }} | ||||||
| @@ -93,8 +93,8 @@ const router = new VueRouter({ | |||||||
|     { path: '/dashboard', component: () => import(/* webpackChunkName: "admin" */ './admin/admin-dashboard.vue') }, |     { path: '/dashboard', component: () => import(/* webpackChunkName: "admin" */ './admin/admin-dashboard.vue') }, | ||||||
|     { path: '/general', component: () => import(/* webpackChunkName: "admin" */ './admin/admin-general.vue') }, |     { path: '/general', component: () => import(/* webpackChunkName: "admin" */ './admin/admin-general.vue') }, | ||||||
|     { path: '/locale', component: () => import(/* webpackChunkName: "admin" */ './admin/admin-locale.vue') }, |     { path: '/locale', component: () => import(/* webpackChunkName: "admin" */ './admin/admin-locale.vue') }, | ||||||
|  |     { path: '/navigation', component: () => import(/* webpackChunkName: "admin" */ './admin/admin-navigation.vue') }, | ||||||
|     { path: '/pages', component: () => import(/* webpackChunkName: "admin" */ './admin/admin-pages.vue') }, |     { path: '/pages', component: () => import(/* webpackChunkName: "admin" */ './admin/admin-pages.vue') }, | ||||||
|     { path: '/stats', component: () => import(/* webpackChunkName: "admin" */ './admin/admin-stats.vue') }, |  | ||||||
|     { path: '/theme', component: () => import(/* webpackChunkName: "admin" */ './admin/admin-theme.vue') }, |     { path: '/theme', component: () => import(/* webpackChunkName: "admin" */ './admin/admin-theme.vue') }, | ||||||
|     { path: '/groups', component: () => import(/* webpackChunkName: "admin" */ './admin/admin-groups.vue') }, |     { path: '/groups', component: () => import(/* webpackChunkName: "admin" */ './admin/admin-groups.vue') }, | ||||||
|     { path: '/groups/:id', component: () => import(/* webpackChunkName: "admin" */ './admin/admin-groups-edit.vue') }, |     { path: '/groups/:id', component: () => import(/* webpackChunkName: "admin" */ './admin/admin-groups-edit.vue') }, | ||||||
|   | |||||||
							
								
								
									
										171
									
								
								client/components/admin/admin-navigation.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										171
									
								
								client/components/admin/admin-navigation.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,171 @@ | |||||||
|  | <template lang='pug'> | ||||||
|  |   v-container(fluid, fill-height) | ||||||
|  |     v-layout(row wrap) | ||||||
|  |       v-flex(xs12) | ||||||
|  |         .admin-header-icon: v-icon(size='80', color='grey lighten-2') near_me | ||||||
|  |         .headline.primary--text {{$t('admin:navigation.title')}} | ||||||
|  |         .subheading.grey--text {{$t('admin:navigation.subtitle')}} | ||||||
|  |         v-container.pa-0.mt-3(fluid, grid-list-lg) | ||||||
|  |           v-layout(row) | ||||||
|  |             v-flex(style='flex: 0 0 350px;') | ||||||
|  |               v-card | ||||||
|  |                 v-list.primary.py-2(dense, dark) | ||||||
|  |                   draggable | ||||||
|  |                     template(v-for='navItem in navTree') | ||||||
|  |                       v-list-tile(v-if='navItem.kind === "link"', :class='(navItem === current) ? "blue" : ""', @click='selectItem(navItem)') | ||||||
|  |                         v-list-tile-avatar: v-icon {{navItem.icon}} | ||||||
|  |                         v-list-tile-title {{navItem.label}} | ||||||
|  |                       .py-2.clickable(v-else-if='navItem.kind === "divider"', :class='(navItem === current) ? "blue" : ""', @click='selectItem(navItem)') | ||||||
|  |                         v-divider | ||||||
|  |                       v-subheader.pl-4.clickable(v-else-if='navItem.kind === "header"', :class='(navItem === current) ? "blue" : ""', @click='selectItem(navItem)') {{navItem.label}} | ||||||
|  |                 v-card-chin | ||||||
|  |                   v-spacer | ||||||
|  |                   v-menu(offset-y, bottom, min-width='200px') | ||||||
|  |                     v-btn(slot='activator', color='primary', depressed) | ||||||
|  |                       v-icon(left) add | ||||||
|  |                       span Add | ||||||
|  |                     v-list | ||||||
|  |                       v-list-tile(@click='addItem("link")') | ||||||
|  |                         v-list-tile-avatar: v-icon link | ||||||
|  |                         v-list-tile-title Link | ||||||
|  |                       v-list-tile(@click='addItem("header")') | ||||||
|  |                         v-list-tile-avatar: v-icon title | ||||||
|  |                         v-list-tile-title Header | ||||||
|  |                       v-list-tile(@click='addItem("divider")') | ||||||
|  |                         v-list-tile-avatar: v-icon power_input | ||||||
|  |                         v-list-tile-title Divider | ||||||
|  |                   v-btn.ml-2(color='success', depressed) | ||||||
|  |                     v-icon(left) check | ||||||
|  |                     span Save | ||||||
|  |             v-flex | ||||||
|  |               v-card(v-if='current.kind === "link"') | ||||||
|  |                 v-toolbar(dense, color='blue', flat, dark) | ||||||
|  |                   .subheading Edit Link | ||||||
|  |                 v-card-text | ||||||
|  |                   v-text-field( | ||||||
|  |                     outline | ||||||
|  |                     background-color='grey lighten-2' | ||||||
|  |                     label='Label' | ||||||
|  |                     prepend-icon='title' | ||||||
|  |                     v-model='current.label' | ||||||
|  |                   ) | ||||||
|  |                   v-text-field( | ||||||
|  |                     outline | ||||||
|  |                     background-color='grey lighten-2' | ||||||
|  |                     label='Icon' | ||||||
|  |                     prepend-icon='casino' | ||||||
|  |                     v-model='current.icon' | ||||||
|  |                   ) | ||||||
|  |                   v-select( | ||||||
|  |                     outline | ||||||
|  |                     background-color='grey lighten-2' | ||||||
|  |                     label='Target Type' | ||||||
|  |                     prepend-icon='near_me' | ||||||
|  |                     :items='navTypes' | ||||||
|  |                     v-model='current.targetType' | ||||||
|  |                   ) | ||||||
|  |                   v-text-field( | ||||||
|  |                     v-if='current.targetType === "external"' | ||||||
|  |                     outline | ||||||
|  |                     background-color='grey lighten-2' | ||||||
|  |                     label='Target' | ||||||
|  |                     prepend-icon='near_me' | ||||||
|  |                     v-model='current.target' | ||||||
|  |                   ) | ||||||
|  |                 v-card-chin | ||||||
|  |                   v-spacer | ||||||
|  |                   v-btn(color='red', outline) | ||||||
|  |                     v-icon(left) delete | ||||||
|  |                     span Delete Link | ||||||
|  |               v-card(v-else-if='current.kind === "header"') | ||||||
|  |                 v-toolbar(dense, color='blue', flat, dark) | ||||||
|  |                   .subheading Edit Header | ||||||
|  |                 v-card-text | ||||||
|  |                   v-text-field( | ||||||
|  |                     outline | ||||||
|  |                     background-color='grey lighten-2' | ||||||
|  |                     label='Label' | ||||||
|  |                     prepend-icon='title' | ||||||
|  |                     v-model='current.label' | ||||||
|  |                   ) | ||||||
|  |                 v-card-chin | ||||||
|  |                   v-spacer | ||||||
|  |                   v-btn(color='red', outline) | ||||||
|  |                     v-icon(left) delete | ||||||
|  |                     span Delete Header | ||||||
|  |               div(v-else-if='current.kind === "divider"') | ||||||
|  |                 v-btn.mt-0(color='red', outline) | ||||||
|  |                   v-icon(left) delete | ||||||
|  |                   span Delete Divider | ||||||
|  |               v-card(v-else) | ||||||
|  |                 v-card-text.grey--text Select a navigation item on the left. | ||||||
|  |  | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | import draggable from 'vuedraggable' | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |   components: { | ||||||
|  |     draggable | ||||||
|  |   }, | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       navTypes: [ | ||||||
|  |         { text: 'External Link', value: 'external' }, | ||||||
|  |         { text: 'Home', value: 'home' }, | ||||||
|  |         { text: 'Page', value: 'page' }, | ||||||
|  |         { text: 'Search Query', value: 'search' } | ||||||
|  |       ], | ||||||
|  |       navTree: [ | ||||||
|  |         { | ||||||
|  |           kind: 'link', | ||||||
|  |           label: 'Home', | ||||||
|  |           icon: 'home', | ||||||
|  |           targetType: 'home', | ||||||
|  |           target: '/' | ||||||
|  |         } | ||||||
|  |       ], | ||||||
|  |       current: {} | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     addItem(kind) { | ||||||
|  |       let newItem = { | ||||||
|  |         kind | ||||||
|  |       } | ||||||
|  |       switch (kind) { | ||||||
|  |         case 'link': | ||||||
|  |           newItem = { | ||||||
|  |             ...newItem, | ||||||
|  |             label: 'Untitled Link', | ||||||
|  |             icon: 'chevron_right', | ||||||
|  |             targetType: 'home', | ||||||
|  |             target: '/' | ||||||
|  |           } | ||||||
|  |           break | ||||||
|  |         case 'header': | ||||||
|  |           newItem.label = 'Untitled Header' | ||||||
|  |           break | ||||||
|  |       } | ||||||
|  |       this.navTree.push(newItem) | ||||||
|  |       this.current = newItem | ||||||
|  |     }, | ||||||
|  |     selectItem(item) { | ||||||
|  |       this.current = item | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang='scss' scoped> | ||||||
|  |  | ||||||
|  | .clickable { | ||||||
|  |   cursor: pointer; | ||||||
|  |  | ||||||
|  |   &:hover { | ||||||
|  |     background-color: rgba(mc('blue', '500'), .25); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | </style> | ||||||
							
								
								
									
										35
									
								
								client/components/common/nav-sidebar.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								client/components/common/nav-sidebar.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | |||||||
|  | <template lang="pug"> | ||||||
|  |   v-list(dense, :class='color', :dark='dark') | ||||||
|  |     v-list-tile.pt-2(href='/') | ||||||
|  |       v-list-tile-avatar: v-icon home | ||||||
|  |       v-list-tile-title Home | ||||||
|  |     v-divider.my-2 | ||||||
|  |     v-subheader.pl-4 Navigation | ||||||
|  |     v-list-tile | ||||||
|  |       v-list-tile-avatar: v-icon stars | ||||||
|  |       v-list-tile-title The Universe | ||||||
|  |     v-list-tile | ||||||
|  |       v-list-tile-avatar: v-icon directions_boat | ||||||
|  |       v-list-tile-title Ships | ||||||
|  |     v-list-tile | ||||||
|  |       v-list-tile-avatar: v-icon local_airport | ||||||
|  |       v-list-tile-title Airports | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | export default { | ||||||
|  |   props: { | ||||||
|  |     color: { | ||||||
|  |       type: String, | ||||||
|  |       default: 'primary' | ||||||
|  |     }, | ||||||
|  |     dark: { | ||||||
|  |       type: Boolean, | ||||||
|  |       default: true | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   data() { | ||||||
|  |     return {} | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
| @@ -11,21 +11,7 @@ | |||||||
|       :temporary='$vuetify.breakpoint.xs' |       :temporary='$vuetify.breakpoint.xs' | ||||||
|       v-model='navShown' |       v-model='navShown' | ||||||
|       ) |       ) | ||||||
|       v-list(dense) |       nav-sidebar | ||||||
|         v-list-tile.pt-2(href='/') |  | ||||||
|           v-list-tile-avatar: v-icon home |  | ||||||
|           v-list-tile-title Home |  | ||||||
|         v-divider.my-2 |  | ||||||
|         v-subheader.pl-4 Navigation |  | ||||||
|         v-list-tile |  | ||||||
|           v-list-tile-avatar: v-icon stars |  | ||||||
|           v-list-tile-title The Universe |  | ||||||
|         v-list-tile |  | ||||||
|           v-list-tile-avatar: v-icon directions_boat |  | ||||||
|           v-list-tile-title Ships |  | ||||||
|         v-list-tile |  | ||||||
|           v-list-tile-avatar: v-icon local_airport |  | ||||||
|           v-list-tile-title Airports |  | ||||||
|  |  | ||||||
|     v-content |     v-content | ||||||
|       v-toolbar(color='grey lighten-3', flat, dense) |       v-toolbar(color='grey lighten-3', flat, dense) | ||||||
| @@ -33,6 +19,7 @@ | |||||||
|           v-icon(color='grey darken-2', left) menu |           v-icon(color='grey darken-2', left) menu | ||||||
|           span Navigation |           span Navigation | ||||||
|         v-breadcrumbs.pl-0(v-else, divider='/') |         v-breadcrumbs.pl-0(v-else, divider='/') | ||||||
|  |           v-breadcrumbs-item: v-icon home | ||||||
|           v-breadcrumbs-item Universe |           v-breadcrumbs-item Universe | ||||||
|           v-breadcrumbs-item Galaxy |           v-breadcrumbs-item Galaxy | ||||||
|           v-breadcrumbs-item Solar System |           v-breadcrumbs-item Solar System | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user