site:
url: http://localhost:5252
title: Brand Docs
- domains:
+ components:
- name: abc
title: Project ABC
+ url: '#'
versions:
+ - &latest_version_abc
+ url: '#'
+ version: '1.1'
- url: '#'
- string: '1.1'
- latest: true
- - url: '#'
- string: '1.0'
- - name: xyz
+ version: '1.0'
+ latestVersion: *latest_version_abc
+ - &component
+ name: xyz
title: Project XYZ
- selected: true
- versions: &domain_versions
- - url: '#'
- string: '6.0'
- latest: true
- selected: true
- - url: '#'
- string: '5.2'
+ url: /xyz/6.0/index.html
+ versions:
+ - &latest_version_xyz
+ url: /xyz/6.0/index.html
+ version: '6.0'
+ - &component_version
+ url: '#'
+ version: '5.2'
- url: '#'
- string: '5.1'
+ version: '5.1'
- url: '#'
- string: '5.0'
+ version: '5.0'
+ latestVersion: *latest_version_xyz
- name: 123
title: Project 123
+ url: '#'
versions:
+ - &latest_version_123
+ url: '#'
+ version: '2.2'
- url: '#'
- string: '2.2'
- latest: true
- - url: '#'
- string: '2.1'
+ version: '2.1'
- url: '#'
- string: '2.0'
-title: Hardware and Software Requirements
-home: false
-siteRootUrl: /
-editUrl: http://example.com/project-xyz/blob/master/index.adoc
-domain:
- name: xyz
- title: Project XYZ
- type: component
- version:
- string: '6.0'
- versioned: true
- versions: *domain_versions
-breadcrumbs:
-- title: Quickstart
- url: '#'
- currentPath: true
-- title: Hardware and Software Requirements
- url: '#'
- currentPage: true
-versions:
-- string: '6.0'
- url: '#'
-- string: '5.2'
- url: '#'
-- string: '5.1'
- url: '#'
-navigation:
-- title: Project XYZ
- url: '#'
- currentPath: true
- items:
- - title: Quickstart
+ version: '2.0'
+ latestVersion: *latest_version_123
+page:
+ title: Hardware and Software Requirements
+ url: /xyz/5.2/index.html
+ component: *component
+ componentVersion: *component_version
+ version: '5.2'
+ module: ROOT
+ home: false
+ editUrl: http://example.com/project-xyz/blob/master/index.adoc
+ breadcrumbs:
+ - content: Quickstart
url: '#'
- currentPath: true
- items:
- - title: Hardware and Software Requirements
- url: '#'
- currentPage: true
- items: []
- - title: IDE Integration
- url: '#'
- items: []
- - title: Application Tutorial
+ urlType: fragment
+ - content: Hardware and Software Requirements
+ url: /xyz/5.2/index.html
+ urlType: internal
+ versions:
+ - version: '6.0'
url: '#'
- items: []
- - title: Reference
+ - version: '5.2'
url: '#'
+ - version: '5.1'
+ url: '#'
+ navigation:
+ - root: true
+ content: Project XYZ
+ url: '#'
+ urlType: fragment
items:
- - title: Keyboard Shortcuts
+ - content: Quickstart
+ url: '#'
+ urlType: fragment
+ items:
+ - content: Hardware and Software Requirements
+ url: /xyz/5.2/index.html
+ urlType: internal
+ - title: IDE Integration
+ url: '#'
+ urlType: fragment
+ - content: Application Tutorial
url: '#'
- items: []
- - title: Importing and Exporting
+ urlType: fragment
+ - content: Reference
url: '#'
- items: []
+ urlType: fragment
+ items:
+ - content: Keyboard Shortcuts
+ url: '#'
+ urlType: fragment
+ - content: Importing and Exporting
+ url: '#'
+ urlType: fragment
+++ /dev/null
-html.is-clipped--nav {
- overflow-y: hidden;
-}
-
-.navigation-domain {
- flex-grow: 1;
- overflow-y: auto;
- display: flex;
- flex-direction: column;
-}
-
-.navigation-domain:not(.is-active) {
- display: none;
-}
-
-.nav-menu {
- flex-grow: 1;
- min-height: 0;
- /* QUESTION move padding to .navigation-domain? */
- /*
- padding: 0.5rem;
- */
- padding: 0.4rem 0.5rem;
-}
-
-.nav-list {
- list-style: none;
- margin: 0;
- padding: 0;
- width: 100%;
-}
-
-.nav-list .nav-list {
- margin-left: 1em;
-}
-
-.nav-item {
- display: flex;
- align-items: flex-start;
- flex-wrap: wrap;
-}
-
-.nav-item .nav-item {
- padding-top: 0.25em;
-}
-
-.nav-item > .nav-list {
- display: none;
-}
-
-.nav-item[data-depth="0"] > .nav-list,
-.nav-item.is-active > .nav-list {
- display: block;
-}
-
-.nav-toggle {
- background: transparent url(../img/caret.svg) no-repeat left center;
- background-size: 85%;
- border: none;
- cursor: pointer;
- font-size: inherit;
- height: 1.85em;
- outline: none;
- padding: 0;
- width: 1em;
-}
-
-@media (min-width: 769px) {
- .nav-toggle {
- height: 1.6em;
- }
-}
-
-.nav-toggle::-moz-focus-inner {
- border: none;
-}
-
-.nav-item.is-active > .nav-toggle {
- transform: rotate(90deg);
-}
-
-.nav-link,
-.nav-text {
- color: inherit;
- display: inline-block;
- line-height: 1.85;
- margin-left: 1em;
- text-decoration: none;
- padding-left: 0.25em;
-}
-
-@media (min-width: 769px) {
- .nav-link,
- .nav-text {
- line-height: 1.6;
- }
-}
-
-.is-current-page > .nav-link,
-.is-current-page > .nav-text {
- font-weight: 500;
-}
-
-.nav-item[data-depth="0"] > .nav-link,
-.nav-item[data-depth="0"] > .nav-text,
-.nav-item[data-depth="0"] > .nav-list {
- margin-left: 0;
-}
-
-.nav-toggle + .nav-link,
-.nav-toggle + .nav-text {
- margin-left: 0;
-}
-
-.nav-link:hover {
- text-decoration: underline;
-}
-
-.nav-item[data-depth="0"] > .nav-link,
-.nav-item[data-depth="0"] > .nav-text {
- padding-left: 0;
- display: none; /* FIXME temporary */
-}
padding: 0 1.5rem 0 0;
}
-.navigation-explore .domains {
+.navigation-explore .components {
flex-grow: 1;
box-shadow: inset 0 1px 5px #e1e1e1;
background-color: #f0f0f0;
display: block;
}
-.navigation-explore:not(.is-active) .domains {
+.navigation-explore:not(.is-active) .components {
display: none;
}
-.navigation-explore .domain {
+.navigation-explore .component {
display: block;
}
-.navigation-explore .domain + .domain {
+.navigation-explore .component + .component {
margin-top: 0.5rem;
}
-.navigation-explore .domain .title {
+.navigation-explore .component .title {
font-weight: 500;
}
padding-left: 0.5rem;
}
-.navigation-explore .domain .version {
+.navigation-explore .component .version {
display: block;
font-size: 0.95em;
}
-.navigation-explore .domain .version a {
+.navigation-explore .component .version a {
color: #4a4a4a;
text-decoration: none;
white-space: nowrap;
}
-.navigation-explore .domain .version.is-current {
+.navigation-explore .component .version.is-current {
font-weight: 500;
}
-.navigation-explore .domain .version.is-latest a::after {
+.navigation-explore .component .version.is-latest a::after {
content: ' (latest)';
}
-.navigation-explore .domain .version a:hover {
+.navigation-explore .component .version a:hover {
text-decoration: underline;
}
-.navigation-explore .domain .version + .version {
+.navigation-explore .component .version + .version {
padding-left: 0.5em;
}
--- /dev/null
+html.is-clipped--nav {
+ overflow-y: hidden;
+}
+
+.navigation-menu {
+ flex-grow: 1;
+ overflow-y: auto;
+ display: flex;
+ flex-direction: column;
+}
+
+.navigation-menu:not(.is-active) {
+ display: none;
+}
+
+.nav-menu {
+ flex-grow: 1;
+ min-height: 0;
+ /* QUESTION move padding to .navigation-menu? */
+ /*
+ padding: 0.5rem;
+ */
+ padding: 0.4rem 0.5rem;
+}
+
+.nav-list {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+ width: 100%;
+}
+
+.nav-list .nav-list {
+ margin-left: 1em;
+}
+
+.nav-item {
+ display: flex;
+ align-items: flex-start;
+ flex-wrap: wrap;
+}
+
+.nav-item .nav-item {
+ padding-top: 0.25em;
+}
+
+.nav-item > .nav-list {
+ display: none;
+}
+
+.nav-item[data-depth="0"] > .nav-list,
+.nav-item.is-active > .nav-list {
+ display: block;
+}
+
+.nav-toggle {
+ background: transparent url(../img/caret.svg) no-repeat left center;
+ background-size: 85%;
+ border: none;
+ cursor: pointer;
+ font-size: inherit;
+ height: 1.85em;
+ outline: none;
+ padding: 0;
+ width: 1em;
+}
+
+@media (min-width: 769px) {
+ .nav-toggle {
+ height: 1.6em;
+ }
+}
+
+.nav-toggle::-moz-focus-inner {
+ border: none;
+}
+
+.nav-item.is-active > .nav-toggle {
+ transform: rotate(90deg);
+}
+
+.nav-link,
+.nav-text {
+ color: inherit;
+ display: inline-block;
+ line-height: 1.85;
+ margin-left: 1em;
+ text-decoration: none;
+ padding-left: 0.25em;
+}
+
+@media (min-width: 769px) {
+ .nav-link,
+ .nav-text {
+ line-height: 1.6;
+ }
+}
+
+.is-current-page > .nav-link,
+.is-current-page > .nav-text {
+ font-weight: 500;
+}
+
+.nav-item[data-depth="0"] > .nav-link,
+.nav-item[data-depth="0"] > .nav-text,
+.nav-item[data-depth="0"] > .nav-list {
+ margin-left: 0;
+}
+
+.nav-toggle + .nav-link,
+.nav-toggle + .nav-text {
+ margin-left: 0;
+}
+
+.nav-link:hover {
+ text-decoration: underline;
+}
+
+.nav-item[data-depth="0"] > .nav-link,
+.nav-item[data-depth="0"] > .nav-text {
+ padding-left: 0;
+ display: none; /* FIXME temporary */
+}
@import "base.css";
@import "main.css";
@import "navigation.css";
-@import "navigation-domain.css";
+@import "navigation-menu.css";
@import "navigation-explore.css";
@import "toolbar.css";
@import "breadcrumbs.css";
--- /dev/null
+'use strict'
+
+const TAG_ALL_RX = /<[^>]+>/g
+module.exports = (html) => html.replace(TAG_ALL_RX, '')
+++ /dev/null
-'use strict'
-
-module.exports = (domain) => domain.versioned && domain.versions.length > 1
+++ /dev/null
-'use strict'
-
-// FIXME the UI model should be prepopulated with this collection
-module.exports = (domains, domainName, otherPageVersions) => {
- const domain = domains.find((candidate) => candidate.name === domainName)
- const pageVersions = []
- domain.versions.forEach((domainVersion) => {
- const pageVersion = otherPageVersions.find((candidate) => candidate.string === domainVersion.string)
- if (pageVersion) {
- pageVersions.push(pageVersion)
- } else {
- pageVersions.push(Object.assign({ missing: true }, domainVersion))
- }
- })
-
- return pageVersions
-}
--- /dev/null
+'use strict'
+
+const path = require('path')
+
+// TODO memoize
+module.exports = (from, to) => {
+ if (to === '#') {
+ return to
+ } else if (to.charAt(to.length - 1) === '/') {
+ return from === to ? './' : path.relative(path.dirname(from + '.'), to) + '/'
+ } else {
+ return path.relative(path.dirname(from + '.'), to)
+ }
+}
var navContainer = document.querySelector('.navigation-container')
var navToggle = document.querySelector('.navigation-toggle')
- var domainNav = navContainer.querySelector('[data-panel=domain]')
+ var menuPanel = navContainer.querySelector('[data-panel=menu]')
+ var currentPageItem = document.querySelector('.nav-menu .is-current-page')
var state = getState() || {}
navContainer.querySelector('.current').addEventListener('click', function () {
var currentPanel = document.querySelector('.navigation .is-active[data-panel]')
- var selectPanel = currentPanel.dataset.panel === 'domain' ? 'explore' : 'domain'
+ var selectPanel = currentPanel.dataset.panel === 'menu' ? 'explore' : 'menu'
currentPanel.classList.toggle('is-active')
document.querySelector('.navigation [data-panel=' + selectPanel + ']').classList.toggle('is-active')
})
// don't let click events propagate outside of navigation container
navContainer.addEventListener('click', concealEvent)
+ if (currentPageItem) activateCurrentPath(currentPageItem)
+
find('.nav-menu').forEach(function (navTree) {
var panel = navTree.parentElement.dataset.panel
find('.nav-item', navTree).forEach(function (item, idx) {
saveState()
- scrollItemIntoView(state.scroll || 0, domainNav, document.querySelector('.nav-menu .is-current-page .nav-link'))
- domainNav.addEventListener('scroll', function () {
- state.scroll = Math.round(domainNav.scrollTop)
+ scrollItemIntoView(state.scroll || 0, menuPanel, currentPageItem && currentPageItem.querySelector('.nav-link'))
+
+ menuPanel.addEventListener('scroll', function () {
+ state.scroll = Math.round(menuPanel.scrollTop)
saveState()
})
+ function activateCurrentPath (navItem) {
+ var ancestorClasses
+ var ancestor = navItem.parentNode
+ while (!(ancestorClasses = ancestor.classList).contains('nav-menu')) {
+ if (ancestor.tagName === 'LI' && ancestorClasses.contains('nav-item')) {
+ ancestorClasses.add('is-active', 'is-current-path')
+ }
+ ancestor = ancestor.parentNode
+ }
+ }
+
function toggleNavigation (e) {
if (navToggle.classList.contains('is-active')) {
return closeNavigation(e)
})
}
- function getState (domain, version) {
+ function getState (component, version) {
var data = window.sessionStorage.getItem('nav-state')
if (data) {
return JSON.parse(data)
}
function scrollItemIntoView (scrollPosition, parent, el) {
- if (el === null) {
- return (parent.scrollTop = scrollPosition)
- }
+ if (!el) return (parent.scrollTop = scrollPosition)
var margin = 10
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>{{title}}{{#if site.title}} :: {{site.title}}{{/if}}</title>
- <link rel="stylesheet" href="{{or uiRootPath themeRootPath}}/css/site.css">
+ <title>{{detag page.title}}{{#if site.title}} :: {{site.title}}{{/if}}</title>
+ <link rel="stylesheet" href="{{uiRootPath}}/css/site.css">
{{> head}}
</head>
<body class="status-404">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>{{title}}{{#if site.title}} :: {{site.title}}{{/if}}</title>
- {{#if canonicalUrl}}
- <link rel="canonical" href="{{canonicalUrl}}">
+ <title>{{detag page.title}}{{#if site.title}} :: {{site.title}}{{/if}}</title>
+ {{#if page.canonicalUrl}}
+ <link rel="canonical" href="{{page.canonicalUrl}}">
{{/if}}
- {{#if description}}
- <meta name="description" content="{{description}}">
+ {{#if page.description}}
+ <meta name="description" content="{{page.description}}">
{{/if}}
- {{#if keywords}}
- <meta name="keywords" content="{{keywords}}">
+ {{#if page.keywords}}
+ <meta name="keywords" content="{{page.keywords}}">
{{/if}}
- <link rel="stylesheet" href="{{or uiRootPath themeRootPath}}/css/site.css">
+ <link rel="stylesheet" href="{{uiRootPath}}/css/site.css">
{{> head}}
</head>
<body class="article">
<article class="doc">
-<h1>{{title}}</h1>
-{{{contents}}}
+<h1>{{{page.title}}}</h1>
+{{{page.contents}}}
</article>
<nav class="crumbs" role="navigation" aria-label="breadcrumbs">
<ul>
- {{#if domain.title}}
- {{#unless (or domain.root (eq domain.title breadcrumbs.0.title))}}
- <li class="crumb"><a href="{{{domain.url}}}">{{{domain.title}}}</a></li>
+ {{#if component.title}}
+ {{#unless (or component.root (eq page.breadcrumbs.0.content component.title))}}
+ <li class="crumb"><a href="{{{relativize page.url component.url}}}">{{{component.title}}}</a></li>
{{/unless}}
{{/if}}
- {{#each breadcrumbs}}
- {{#if ./url}}
- <li class="crumb"><a href="{{{./url}}}">{{{./title}}}</a></li>
+ {{#each page.breadcrumbs}}
+ {{#if (and ./url (eq ./urlType 'internal'))}}
+ <li class="crumb"><a href="{{{relativize @root.page.url ./url}}}">{{{./content}}}</a></li>
{{else}}
- <li class="crumb">{{{./title}}}</li>
+ <li class="crumb">{{{./content}}}</li>
{{/if}}
{{/each}}
</ul>
-<script src="{{or uiRootPath themeRootPath}}/js/site.js"></script>
-<script src="{{or uiRootPath themeRootPath}}/js/vendor/highlight.js"></script>
+<script src="{{uiRootPath}}/js/site.js"></script>
+<script src="{{uiRootPath}}/js/vendor/highlight.js"></script>
<script>hljs.initHighlighting()</script>
<header class="header" role="banner">
<nav class="navbar">
<div class="navbar-brand">
- <a class="navbar-item" href="{{or site.url siteRootUrl}}">{{site.title}}</a>
+ <a class="navbar-item" href="{{or site.url (or siteRootUrl siteRootPath)}}">{{site.title}}</a>
<button class="navbar-burger" data-target="topbar-nav">
<span></span>
<span></span>
+++ /dev/null
-<div class="navigation-domain is-active" data-panel="domain">
- <nav class="nav-menu">
-{{> navigation-tree}}
- </nav>
-</div>
<div class="navigation-explore" data-panel="explore">
<div class="current">
- <span class="title">{{domain.title}}</span>
- <span class="version">{{domain.version.string}}</span>
+ <span class="title">{{page.component.title}}</span>
+ <span class="version">{{page.version}}</span>
</div>
- <ul class="domains">
- {{#each site.domains}}
- <li class="domain{{#if ./selected}} is-current{{/if}}">
+ <ul class="components">
+ {{#each site.components}}
+ <li class="component{{#if (eq this @root.page.component)}} is-current{{/if}}">
<span class="title">{{{./title}}}</span>
<ul class="versions">
{{#each ./versions}}
- <li class="version{{#if ./selected}} is-current{{/if}}{{#if ./latest}} is-latest{{/if}}">
- <a href="{{{./url}}}">{{./string}}</a>
+ <li class="version{{#if (and (eq ../this @root.page.component) (eq this @root.page.componentVersion))}} is-current{{/if}}{{#if (eq this ../latestVersion)}} is-latest{{/if}}">
+ <a href="{{{relativize @root.page.url ./url}}}">{{./version}}</a>
</li>
{{/each}}
</ul>
--- /dev/null
+<div class="navigation-menu is-active" data-panel="menu">
+ <nav class="nav-menu">
+{{> navigation-tree navigation=page.navigation}}
+ </nav>
+</div>
{{#if navigation.length}}
<ul class="nav-list">
{{#each navigation}}
- <li class="nav-item{{#if ./currentPath}} is-active is-current-path{{/if}}{{#if ./currentPage}} is-current-page{{/if}}" data-depth="{{#if ../level}}{{../level}}{{else}}0{{/if}}">
+ <li class="nav-item{{#if (eq @root.page.url ./url)}} is-current-page{{/if}}" data-depth="{{or ../level 0}}">
{{#if (and ../level ./items.length)}}
<button class="nav-toggle"></button>
{{/if}}
{{#if ./url}}
- <a class="nav-link" href="{{{./url}}}">{{{./title}}}</a>
+ <a class="nav-link" href="{{#if (eq ./urlType 'internal')}}{{{relativize @root.page.url ./url}}}{{else}}{{{./url}}}{{/if}}">{{{./content}}}</a>
{{else}}
- <span class="nav-text">{{{./title}}}</span>
+ <span class="nav-text">{{{./content}}}</span>
{{/if}}
{{> navigation-tree navigation=./items level=(inc ../level)}}
</li>
<div class="navigation-container">
<aside class="navigation" role="navigation">
<div class="panels">
-{{> navigation-domain}}
+{{> navigation-menu}}
{{> navigation-explore}}
</div>
</aside>
-{{#if (has-versions domain)}}
+{{#if page.versions}}
<div class="page-versions">
- <button class="versions-menu-toggle" title="Show other versions of page">{{domain.version.string}}</button>
+ <button class="versions-menu-toggle" title="Show other versions of page">{{page.version}}</button>
<div class="versions-menu">
- {{#each (page-versions site.domains domain.name versions)}}
- <a class="version{{#if (eq ./string ../domain.version.string)}} is-current{{/if}}{{#if ./missing}} is-missing{{/if}}" href="{{{./url}}}">{{./string}}</a>
+ {{#each page.versions}}
+ <a class="version{{#if (eq ./version @root.page.version)}} is-current{{/if}}{{#if ./missing}} is-missing{{/if}}" href="{{{relativize @root.page.url ./url}}}">{{./version}}</a>
{{/each}}
</div>
</div>
<div class="toolbar" role="navigation">
<button class="navigation-toggle"></button>
{{#if siteRootUrl}}
- <a href="{{siteRootUrl}}" class="home-link{{#if home}} is-current{{/if}}"></a>
+ <a href="{{siteRootUrl}}" class="home-link{{#if page.home}} is-current{{/if}}"></a>
{{/if}}
{{> breadcrumbs}}
{{> page-versions}}
- <div class="edit-this-page"><a href="{{editUrl}}">Edit this Page</a></div>
+ <div class="edit-this-page"><a href="{{page.editUrl}}">Edit this Page</a></div>
</div>
module.exports = async (src, dest, siteSrc, siteDest) => {
const [layouts] = await Promise.all([compileLayouts(src), registerPartials(src), registerHelpers(src)])
- const mockUIModel = loadSampleUIModel(siteSrc)
+ const uiModel = loadSampleUiModel(siteSrc)
vfs
.src('**/*.html', { base: siteSrc, cwd: siteSrc })
map((file, next) => {
const compiledLayout = layouts[file.stem === '404' ? '404.hbs' : 'default.hbs']
const siteRootPath = path.relative(path.dirname(file.path), path.resolve(siteSrc))
- mockUIModel['siteRootPath'] = siteRootPath
- mockUIModel['siteRootUrl'] = path.join(siteRootPath, 'index.html')
- mockUIModel['uiRootPath'] = path.join(siteRootPath, '_')
- mockUIModel['contents'] = file.contents.toString().trimRight()
- file.contents = Buffer.from(compiledLayout(mockUIModel))
+ uiModel.siteRootPath = siteRootPath
+ uiModel.siteRootUrl = path.join(siteRootPath, 'index.html')
+ uiModel.uiRootPath = path.join(siteRootPath, '_')
+ uiModel.page.contents = file.contents.toString().trim()
+ file.contents = Buffer.from(compiledLayout(uiModel))
next(null, file)
})
)
})
}
-function loadSampleUIModel (siteSrc) {
+function loadSampleUiModel (siteSrc) {
return yaml.safeLoad(fs.readFileSync(path.join(siteSrc, 'ui-model.yml'), 'utf8'))
}