diff --git a/bin/args.js b/bin/args.js index ebb81dad..ab3a1bd4 100644 --- a/bin/args.js +++ b/bin/args.js @@ -10,6 +10,7 @@ module.exports = require('nomnom') css: { metavar: 'FILE', help: 'Write Emu CSS dependencies to FILE' }, js: { metavar: 'FILE', help: 'Write Emu JS dependencies to FILE' }, toc: { flag: true, help: 'Don\'t include the table of contents' }, + oldToc: { full: 'old-toc', name: 'old-toc', flag: true, help: 'Use the old table of contents styling' }, verbose: { flag: true, default: false, help: 'Display document build progress' }, version: { abbr: 'v', diff --git a/bin/ecmarkup.js b/bin/ecmarkup.js index 6c90d720..b211c094 100644 --- a/bin/ecmarkup.js +++ b/bin/ecmarkup.js @@ -30,6 +30,6 @@ ecmarkup.build(args.infile, fetch, args).then(function (spec) { } if (args.js) { - fs.writeFileSync(args.js, fs.readFileSync(Path.join(__dirname, '../js/ecmarkup.js'))); + fs.writeFileSync(args.js, fs.readFileSync(Path.join(__dirname, '../js/menu.js'))); } }); diff --git a/css/elements.css b/css/elements.css index 67441cbb..ac1590e3 100644 --- a/css/elements.css +++ b/css/elements.css @@ -1,5 +1,4 @@ html { - padding: 0 7em; } body { @@ -8,8 +7,13 @@ body { font-family: Cambria, Palatino Linotype, Palatino, Liberation Serif, serif; padding: 0; color: #333; - max-width: 65em; - margin: 0 auto; + max-width: 844px; + margin: 0 0 0 31%; + overflow-x: hidden; +} + +body.oldtoc { + margin: 0 auto; } a { @@ -327,3 +331,146 @@ del { del.block { display: block; } + +/* Menu Styles */ +#menu-toggle { + font-size: 2em; + + position: fixed; + top: 0; + left: 0; + width: 1.5em; + height: 1.5em; + z-index: 3; + visibility: hidden; + + background-color: #111; + color: #B6C8E4; + + line-height: 1.5em; + text-align: center; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none;; + + cursor: pointer; +} + +#menu { + position: fixed; + left: 0; + top: 0; + height: 100%; + width: 24%; + z-index: 2; + overflow-x: hidden; + overflow-y: auto; + box-sizing: border-box; + + background-color: #111; + + transition: opacity 0.1s linear; +} + +#menu.active { + display: block; + opacity: 1; +} + +#menu-toc > ol { + padding: 0; +} + +#menu-toc > ol , #menu-toc > ol ol { + list-style-type: none; +} + +#menu-toc > ol ol { + padding-left: 0.75em; +} + +#menu-toc li { + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; +} + +#menu-toc .item-toggle { + display: inline-block; + transform: rotate(-45deg) translate(-5px, -5px); + transition: transform 0.1s ease; + width: 1em; + + color: #555F6E; + + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none;; + + cursor: pointer; +} + +#menu-toc .item-toggle-none { + display: inline-block; + width: 1em; +} + +#menu-toc li.active > .item-toggle { + transform: rotate(0); +} + +#menu-toc li > ol { + display: none; +} + +#menu-toc li.active > ol { + display: block; +} + +#menu-toc li > a { + padding-left: 0.25em; + color: #B6C8E4; +} + +@media (max-width: 1366px) { + body { + margin: 0 0 0 150px; + } + + #menu { + display: none; + padding-top: 2em; + width: 323px; + } + + #menu-toggle { + visibility: visible; + } +} + +@media only screen and (max-width: 800px) { + body { + margin: 2em 10px 0 10px; + } + + #menu { + width: 100%; + } + + h1 .secnum { + display: inline; + position: inherit; + left: 0; + right: 0; + } + + h1 .secnum:empty { + margin: 0; padding: 0; + } +} diff --git a/js/menu.js b/js/menu.js new file mode 100644 index 00000000..796e056c --- /dev/null +++ b/js/menu.js @@ -0,0 +1,36 @@ +"use strict"; + +function Menu() { + this.$toggle = document.getElementById('menu-toggle'); + this.$menu = document.getElementById('menu'); + + this.$toggle.addEventListener('click', this.toggle.bind(this)); + + var tocItems = this.$menu.querySelectorAll('#menu-toc li'); + for (var i = 0; i < tocItems.length; i++) { + var $item = tocItems[i]; + $item.addEventListener('click', function($item, event) { + $item.classList.toggle('active'); + event.stopPropagation(); + }.bind(null, $item)); + } + + var tocLinks = this.$menu.querySelectorAll('#menu-toc li > a'); + for (var i = 0; i < tocLinks.length; i++) { + var $link = tocLinks[i]; + $link.addEventListener('click', function(event) { + this.toggle(); + event.stopPropagation(); + }.bind(this)); + } +} + +Menu.prototype.toggle = function () { + this.$menu.classList.toggle("active"); +} + +function init() { + var menu = new Menu(); +} + +document.addEventListener('DOMContentLoaded', init); diff --git a/lib/Menu.js b/lib/Menu.js new file mode 100644 index 00000000..1fdbbbcc --- /dev/null +++ b/lib/Menu.js @@ -0,0 +1,25 @@ +'use strict'; + +const Builder = require('./Builder'); +const Toc = require('./Toc'); + +module.exports = class Menu extends Builder { + build() { + const toc = Toc.build(this.spec, true); + const tocContainer = this.spec.doc.createElement('div'); + tocContainer.setAttribute('id', 'menu-toc'); + tocContainer.innerHTML = toc; + + const menuContainer = this.spec.doc.createElement('div'); + menuContainer.setAttribute('id', 'menu'); + menuContainer.appendChild(tocContainer); + + this.spec.doc.body.insertBefore(menuContainer, this.spec.doc.body.firstChild); + + const menuToggle = this.spec.doc.createElement('div'); + menuToggle.setAttribute('id', 'menu-toggle'); + menuToggle.textContent = '☰'; + + this.spec.doc.body.insertBefore(menuToggle, this.spec.doc.body.firstChild); + } +}; diff --git a/lib/Spec.js b/lib/Spec.js index 6c76e915..eaaa740c 100644 --- a/lib/Spec.js +++ b/lib/Spec.js @@ -13,6 +13,7 @@ const Algorithm = require('./Algorithm'); const Dfn = require('./Dfn'); const Note = require('./Note'); const Toc = require('./Toc'); +const Menu = require('./Menu'); const Production = require('./Production'); const ProdRef = require('./ProdRef'); const Grammar = require('./Grammar'); @@ -124,8 +125,15 @@ module.exports = class Spec { if (this.opts.toc) { p = p.then(function() { this._log('Building table of contents...'); - const tb = new Toc(this); - return tb.build(); + + let toc; + + if (this.opts.oldToc) { + toc = new Toc(this); + } else { + toc = new Menu(this); + } + return toc.build(); }.bind(this)); } @@ -311,4 +319,3 @@ function assign(target, source) { target[k] = source[k]; }); } - diff --git a/lib/Toc.js b/lib/Toc.js index 90029c22..f2f7a0bb 100644 --- a/lib/Toc.js +++ b/lib/Toc.js @@ -9,26 +9,42 @@ module.exports = class Toc extends Builder { return; } - const html = buildToc(this.spec); + const html = Toc.build(this.spec); const tocContainer = this.spec.doc.createElement('div'); tocContainer.innerHTML = '
diff --git a/test/build.js b/test/build.js index 01bf4376..7aa3b647 100644 --- a/test/build.js +++ b/test/build.js @@ -4,8 +4,8 @@ const Promise = require('bluebird'); const build = require('../lib/ecmarkup').build; -const doc = ''; -const out = '\n hi
Table of Contents
'; +const doc = ' 1hi#
toc: false'; +const out = '\n hi
'; function fetch(file) { if (file.match(/\.json$/)) { return '{}'; diff --git a/test/clauses.html b/test/clauses.html index 8f4db30e..c0fa37c5 100644 --- a/test/clauses.html +++ b/test/clauses.html @@ -1,3 +1,4 @@ + 1hi#
oldToc: trueIntro
diff --git a/test/clauses.html.baseline b/test/clauses.html.baseline index 77279be2..280a136e 100644 --- a/test/clauses.html.baseline +++ b/test/clauses.html.baseline @@ -1,5 +1,6 @@ - Table of Contents
+ + Table of Contents
Intro#
Sub Intro#
diff --git a/test/test.html.baseline b/test/test.html.baseline index 812ca19e..223db364 100644 --- a/test/test.html.baseline +++ b/test/test.html.baseline @@ -1,7 +1,7 @@ -Table of Contents
+ Intro#
Sub Intro#