Skip to content

Commit

Permalink
feat: improve navigation structure (#501)
Browse files Browse the repository at this point in the history
  • Loading branch information
farnabaz authored Jun 23, 2021
1 parent 8875b7c commit bd0d9ad
Show file tree
Hide file tree
Showing 6 changed files with 105 additions and 67 deletions.
17 changes: 8 additions & 9 deletions src/core/runtime/composables/navigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,16 @@ export const useDocusNavigation = ({ context, state, api }: DocusAddonContext) =
const nav = state.navigation[locale || app.i18n.locale] || []

let items = nav
let match
let match: NavItem

// The deepest exclusive navigation that can be found based on `from`
let exclusiveContent
let exclusiveContent: NavItem
// Parent of exclusive Content
let parent
let parent: NavItem

// `from` parameter handling
if (from) {
let lastMatch
let lastMatch: NavItem

const paths = from.split('/')

Expand All @@ -63,15 +63,15 @@ export const useDocusNavigation = ({ context, state, api }: DocusAddonContext) =

// Remember last matched content
// This content will use as navigation parent if it has an exclusive decendant
if (match && !match.shadow) {
if (match && match.page) {
lastMatch = match
}

// Find matched content
match = links.find(item => item.to.split('/')[index] === path)
if (match) {
// Update parent and exclusiveContent if the matched content marked as exclusive navigation
if (match && match.navigation && match.navigation.exclusive) {
if (match && match.exclusive) {
parent = lastMatch || parent
exclusiveContent = match
}
Expand All @@ -94,7 +94,6 @@ export const useDocusNavigation = ({ context, state, api }: DocusAddonContext) =
// matched page info
title: exclusiveContent && exclusiveContent.title,
to: exclusiveContent && exclusiveContent.to,
navigation: exclusiveContent ? exclusiveContent.navigation : {},
// matched parent
parent,
// filter children
Expand All @@ -108,7 +107,7 @@ export const useDocusNavigation = ({ context, state, api }: DocusAddonContext) =
function filterLinks(nodes: NavItem[], maxDepth: number, currentDepth: number) {
return nodes.filter(node => {
// Navigation as false means that we want that link to be hidden from navigation.
if (node.navigation === false) return false
if (node.hidden) return false

// We don't want to show drafts.
if (node.draft === true) return false
Expand All @@ -117,7 +116,7 @@ export const useDocusNavigation = ({ context, state, api }: DocusAddonContext) =
if (currentDepth && maxDepth > currentDepth) return false

// Check if marked as nested, if so children will be empty
if (node.navigation.nested === false) node.children = []
if (node.nested === false) node.children = []

// Loop on current node children if exists
node.children =
Expand Down
24 changes: 17 additions & 7 deletions src/core/runtime/composables/templates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,15 @@ export const useDocusTemplates = (
currentNav: ComputedRef<DocusCurrentNav>
) => {
function getPageTemplate(page: DocusDocument) {
let template = typeof page.template === 'string' ? page.template : page.template?.self

let template =
/**
* Use template defined in page data
*/
typeof page.template === 'string' ? page.template : page.template?.self

/**
* Look for template in parent pages
*/
if (!template) {
// Fetch from nav (root to link) and fallback to settings.template
const slugs: string[] = page.to.split('/').filter(Boolean).slice(0, -1) // no need to get latest slug since it is current page
Expand All @@ -22,17 +29,20 @@ export const useDocusTemplates = (
const link = api.findLink(links, to)

if (link?.template) {
template = link.template.nested
template = link.template || template
}

if (!link?.children) {
return
}
if (!link?.children) return

links = link.children
})
}

template = template || state.settings.template
/**
* Use global template if template is not defined in page data or in parent pages
*/
if (!template) {
template = state.settings.template
}

template = pascalCase(template)
Expand Down
55 changes: 26 additions & 29 deletions src/core/utils/navigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,34 +22,36 @@ const getPageLink = (page: any): NavItem => {

const to = withoutTrailingSlash(page.to || `/${slug}`)

let navigation = typeof page.navigation === 'string' ? { slot: page.navigation } : page.navigation

if (navigation !== false) {
navigation = {
title: page.title || slugToTitle(to.split('/').pop()) || '',
slot: '',
nested: true,
...navigation
}
}

const template =
typeof page.template === 'string' ? { self: page.template, nested: `${page.template}-post` } : page.template

return {
const item: NavItem = {
slug,
to,
shadow: !!page.shadow,
title: page.title,
draft: page.draft,
template,
meta: {
icon: page.icon,
description: page.description
},
navigation,
children: []
page: !!page.dir,
children: [],
title: page.title || slugToTitle(to.split('/').pop()) || '',
...page.navigation
}

if (page.draft) {
item.draft = true
}

if (page.icon) {
item.icon = page.icon
}

if (template) {
item.template = template.nested
}

// set `hidden = true` if navigation is disabled for the page
if (page.navigation === false) {
item.hidden = true
}

return item
}

/**
Expand Down Expand Up @@ -121,10 +123,6 @@ function createNav(pages: any[]) {
if (_page.slug !== '') dirs = dirs.slice(0, -1)

if (!dirs.length) {
if ($page.navigation) {
$page.navigation.slot = $page.navigation.slot || 'header'
}

return links.push($page)
}

Expand Down Expand Up @@ -156,9 +154,8 @@ function createNav(pages: any[]) {

// If index page, merge also with parent for metadata
if (!_page.slug) {
if (dirs.length === 1 && $page.navigation) {
$page.navigation.slot = $page.navigation.slot || 'header'
$page.navigation.exclusive = $page.navigation.exclusive || false
if (dirs.length === 1) {
$page.exclusive = $page.exclusive || false
}

mergeLinks(lastLink, $page)
Expand Down
10 changes: 5 additions & 5 deletions src/defaultTheme/components/molecules/AsideNavigation.vue
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,13 @@
<ul>
<template v-for="link in links">
<AsideNavigationItem
v-if="link.navigation.children !== false && link.children.length"
:key="link.navigation.title"
:title="link.navigation.title"
v-if="link.nested !== false && link.children.length"
:key="link.to"
:title="link.title"
:docs="link.children"
:collapse="link.navigation.collapse"
:collapsed="link.collapse === true"
/>
<AsideNavigationItem v-else :key="link.navigation.title" :docs="[link]" />
<AsideNavigationItem v-else :key="link.to" :docs="[link]" />
</template>
</ul>
<AsideBottom />
Expand Down
6 changes: 4 additions & 2 deletions src/defaultTheme/components/molecules/AsideNavigationItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<ul v-if="!isCollapsed || isActive" class="mb-2 ml-2">
<li v-for="doc of docs" :key="doc.to">
<NuxtLink
:to="$contentLocalePath(doc.navigation.redirect || doc.to)"
:to="$contentLocalePath(doc.redirect || doc.to)"
class="block w-full"
:class="[
$docus.isLinkActive(doc.to)
Expand All @@ -31,7 +31,9 @@
{{ doc.icon }}
</InjectComponent>

<span> {{ doc.navigation.title }} </span>
<span>
{{ doc.title }}
</span>

<ClientOnly>
<span v-if="doc.draft" class="w-2 h-2 ml-2 bg-yellow-500 rounded-full opacity-75" />
Expand Down
60 changes: 45 additions & 15 deletions src/types/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,31 +21,61 @@ export interface Toc {

// Navigation
export interface NavItemNavigationConfig {
/**
* Navigation title
*/
title: string
/**
* If set to `false`, the nested pages will not display in Docus navigation menus
*/
nested: boolean
slot: string
/**
* If set to `true`, other pages will not show in the left menu when user visiting the page or its nested pages.
*/
exclusive: boolean
// Collapse aside navigation by default
/**
* If set to `true` in an `index.md`, the category will be collapsed by default in aside navigation.
*/
collapse: boolean
// Useful for directories `index.md` which are empty pages, to get redirect to another page
/**
* If set in an `index.md`, the page will redirect to the specified path when loaded, can be useful for empty categories pages.
*/
redirect: string
}
export interface NavItem {

export interface NavItem extends NavItemNavigationConfig {
/**
* Page slug
*/
slug: string
/**
* full path of page
*/
to: string
title: string
shadow: boolean
/**
* Shows if the page is draft or not
*/
draft?: boolean
template?: {
self: string
nested: string
}
navigation: NavItemNavigationConfig | false
/**
* Provide template name that should use to render the page
*/
template?: string
/**
* Shows if this nav belogs to a real page or not
*/
page: boolean
/**
* Small Icon that shows before page title
*/
icon?: string
/**
* If set to `false`, the page will not show in navigation menus
*/
hidden: boolean
/**
* Child pages
*/
children: NavItem[]
meta: {
icon?: string
description?: string
}
}

export type PermissiveContext = Context & { [key: string]: any }
Expand Down

1 comment on commit bd0d9ad

@vercel
Copy link

@vercel vercel bot commented on bd0d9ad Jun 23, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.