diff options
author | Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com> | 2021-10-31 17:01:14 +0300 |
---|---|---|
committer | Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com> | 2021-11-03 19:22:49 +0300 |
commit | 3c9eb0a463fbc386cb3087c455d2f71d84b5027f (patch) | |
tree | c831c8cc6f9332803db7f5c05767270bc6aaeb4a | |
parent | 0168f8e5ac0e90549f92fc1512bea95a2ac3fa14 (diff) |
Rewrite to use AlpineJS
29 files changed, 529 insertions, 462 deletions
@@ -1,3 +1,5 @@ docuapi public/ node_modules +.hugo_build.lock +assets/jsconfig.json
\ No newline at end of file @@ -1,6 +1,6 @@ [![Netlify Status](https://api.netlify.com/api/v1/badges/49111249-0a1a-4b5a-a3ab-45d00732fdb3/deploy-status)](https://app.netlify.com/sites/docuapi/deploys) -**DocuAPI** is a beautiful multilingual API documentation theme for [Hugo](http://gohugo.io/). This theme is built on top of the beautiful work of [Robert Lord](https://github.com/lord) and others on the [Slate](https://github.com/slatedocs/slate) project ([Apache 2 License](https://github.com/slatedocs/slate/blob/master/LICENSE)). +**DocuAPI** is a beautiful multilingual API documentation theme for [Hugo](http://gohugo.io/). This theme is built on top of the beautiful work of [Robert Lord](https://github.com/lord) and others on the [Slate](https://github.com/slatedocs/slate) project ([Apache 2 License](https://github.com/slatedocs/slate/blob/master/LICENSE)). The JS part has recently been rewritten from Jquery to [AlpineJS](https://alpinejs.dev/). <br/> @@ -12,16 +12,16 @@ ## Use -The client library used to build the ToC does not handle Unicode very well. To get around this in Hugo >= 0.62.2, put this in your site config: +Import the theme in your Hugo config: ```toml -[markup] - [markup.goldmark] - [markup.goldmark.parser] - autoHeadingIDType = "github-ascii" +[[module.imports]] +path = "github.com/bep/docuapi/v2" ``` -**Note:** this theme requires Hugo >= 0.56.0 to run. If you want to edit the SCSS styles, you need: +Note, if you want the older jQuery-versjon, replace the path with `github.com/bep/docuapi`. + +If you want to edit the SCSS styles, you need: * The extended Hugo version. * PostCSS CLI (run `npm install` to install requirements) diff --git a/assets/js/controllers/index.js b/assets/js/controllers/index.js new file mode 100644 index 0000000..afb73b2 --- /dev/null +++ b/assets/js/controllers/index.js @@ -0,0 +1,3 @@ +export * from './lang'; +export * from './search-lunr'; +export * from './toc'; diff --git a/assets/js/controllers/lang.js b/assets/js/controllers/lang.js new file mode 100644 index 0000000..eed1fb8 --- /dev/null +++ b/assets/js/controllers/lang.js @@ -0,0 +1,37 @@ +const debug = 0 ? console.log.bind(console, '[lang]') : function() {}; + +const toggleCodeblockVisibility = function(lang, visible) { + debug('toggleCodeblockVisibility', lang, visible); + document.querySelectorAll(`.highlight code.language-${lang}`).forEach((el) => { + let highlight = el.closest('.highlight'); + highlight.style.display = visible ? 'block' : 'none'; + }); +}; + +export function newLangController() { + return { + tabs: [], + changeLanguage: function(index) { + debug('changeLanguage', index); + let tab = this.tabs[index]; + for (let i = 0; i < this.tabs.length; i++) { + let isActive = i === index; + this.tabs[i].active = isActive; + + toggleCodeblockVisibility(this.tabs[i].key, isActive); + } + }, + initLangs: function(tabs) { + debug('initLangs', tabs); + tabs[0].active = true; + this.tabs = tabs; + + return this.$nextTick(() => { + let first = this.tabs[0]; + // Hide all but the first. + for (let i = 1; i < this.tabs.length; i++) {} + debug('first', first); + }); + } + }; +} diff --git a/assets/js/controllers/search-lunr.js b/assets/js/controllers/search-lunr.js new file mode 100644 index 0000000..9509998 --- /dev/null +++ b/assets/js/controllers/search-lunr.js @@ -0,0 +1,83 @@ +import * as lunr from 'js/lib/lunr.js'; +import { Highlight } from 'js/helpers'; + +function nextUntil(elem, selector) { + var siblings = []; + + elem = elem.nextElementSibling; + + while (elem) { + if (elem.matches(selector)) break; + siblings.push(elem); + elem = elem.nextElementSibling; + } + + return siblings; +} + +export function newSearchController() { + var index; + + var buildIndex = function(config) { + var builder = new lunr.Builder(); + + builder.pipeline.add(lunr.trimmer, lunr.stopWordFilter, lunr.stemmer); + + builder.searchPipeline.add(lunr.stemmer); + + config.call(builder, builder); + return builder.build(); + }; + + function populateIndex() { + index = buildIndex(function() { + this.ref('id'); + this.field('title', { boost: 10 }); + this.field('body'); + this.pipeline.add(lunr.trimmer, lunr.stopWordFilter); + + document.querySelectorAll('h1, h2').forEach((headerEl) => { + let body = ''; + nextUntil(headerEl, 'h1, h2').forEach((el) => { + body = body.concat(' ', el.textContent); + }); + this.add({ + id: headerEl.id, + title: headerEl.textContent, + body: body + }); + }); + }); + } + + let highlight = new Highlight(); + + return { + query: '', + results: [], + init: function() { + return this.$nextTick(() => { + populateIndex(); + this.$watch('query', () => { + this.search(); + }); + }); + }, + search: function() { + highlight.remove(); + let results = index.search(this.query).filter((item) => item.score > 0.0001); + + this.results = results.map((item) => { + var elem = document.getElementById(item.ref); + + return { + title: elem.innerText + }; + }); + + if (this.results.length > 0) { + highlight.apply(new RegExp(this.query, 'i')); + } + } + }; +} diff --git a/assets/js/controllers/toc.js b/assets/js/controllers/toc.js new file mode 100644 index 0000000..075d3e5 --- /dev/null +++ b/assets/js/controllers/toc.js @@ -0,0 +1,100 @@ +'use strict'; + +const debug = 0 ? console.log.bind(console, '[toc]') : function() {}; + +const headerEls = () => document.querySelectorAll('.content h1, .content h2, .content h3'); + +const setProgress = function(self, el) { + let mainEl = document.querySelector('.content'); + let mainHeight = mainEl.offsetHeight; + let mainStart = mainEl.offsetTop; + let progress = Math.round((el.offsetTop - mainStart) / mainHeight * 100); + self.activeHeading.title = el.innerText; + self.activeHeading.progress = progress; +}; + +export function newToCController() { + const setOpenRecursive = function(row, shouldOpen) { + if (!row.sub) { + return false; + } + let isOpen = false; + + row.sub.forEach((rowsub) => { + rowsub.open = shouldOpen(rowsub); + rowsub.active = rowsub.open; + + rowsub.open = rowsub.open || setOpenRecursive(rowsub, shouldOpen); + + if (rowsub.open) { + isOpen = true; + } + }); + + row.active_parent = isOpen; + isOpen = isOpen || shouldOpen(row); + row.open = isOpen; + row.active = shouldOpen(row); + + return isOpen; + }; + + return { + activeHeading: { + title: '', + progress: 0 + }, + showHeading: true, + rows: [], + load: function(rows) { + this.rows = rows; + }, + + transitions: function() { + return { + 'x-transition:enter.duration.500ms': '', + 'x-transition:leave.duration.400ms': '', + 'x-transition.scale.origin.top.left.80': '' + }; + }, + + rowClass: function(row) { + return { + class: `toc-h${row.level}${row.active ? ' active' : ''}${row.active_parent ? ' active-parent' : ''}` + }; + }, + + click: function(row) { + this.rows.forEach((row2) => { + setOpenRecursive(row2, (row3) => { + return row === row3; + }); + }); + }, + + onScroll: function() { + debug('onScroll'); + let scrollpos = window.scrollY; + + headerEls().forEach((el) => { + let offset = el.offsetTop; + + if (offset < scrollpos + 10) { + debug('Set for', el.id); + + this.rows.forEach((row) => { + setOpenRecursive(row, (row) => { + return row.id === el.id; + }); + }); + + setProgress(this, el); + } + + if (window.innerHeight + scrollpos >= document.body.offsetHeight) { + this.activeHeading.progress = 100; + } + }); + } + }; +} diff --git a/assets/js/helpers/highlight.js b/assets/js/helpers/highlight.js new file mode 100644 index 0000000..b460e3b --- /dev/null +++ b/assets/js/helpers/highlight.js @@ -0,0 +1,101 @@ +function walk(el, callback) { + callback(el); + + let node = el.firstChild; + while (node) { + walk(node, callback); + node = node.nextSibling; + } +} + +export class Highlight { + constructor( + opts = { + contentSelector: '.content', + markClass: 'da-highlight-mark' + } + ) { + this.opts = opts; + this.nodeStack = []; + } + + apply(re) { + const treeWalker = document.createTreeWalker( + this.content(), + NodeFilter.SHOW_TEXT, + { + acceptNode: (node) => { + if (node.parentNode.classList.contains(this.opts.markClass)) { + return NodeFilter.FILTER_REJECT; + } + if (/\S/.test(node.data)) { + return NodeFilter.FILTER_ACCEPT; + } + return NodeFilter.FILTER_REJECT; + } + }, + false + ); + + // Firs pass: Collect all the text nodes matching the provided regexp. + // TODO(bep) improve text matching. + let matches = []; + while (treeWalker.nextNode()) { + let node = treeWalker.currentNode; + if (node.data.match(re)) { + matches.push(node); + } + } + + // Second pass: Replace the matches with nodes wrapped in <mark> tags. + matches.forEach((node) => { + // Clone the parent so we can restore it. + let parentClone = node.parentNode.cloneNode(true); + + parentClone.childNodes.forEach((node) => { + if (node.nodeType !== Node.TEXT_NODE) { + return; + } + + let match = node.data.match(re); + if (!match) { + return; + } + + let pos = node.data.indexOf(match[0], match.index); + if (pos === -1) { + return; + } + + let mark = document.createElement('mark'); + mark.classList.add(this.opts.markClass); + + let wordNode = node.splitText(pos); + wordNode.splitText(match[0].length); + let wordClone = wordNode.cloneNode(true); + + mark.appendChild(wordClone); + parentClone.replaceChild(mark, wordNode); + }); + + if (node.parentNode && node.parentNode.parentNode) { + this.nodeStack.push({ + old: node.parentNode, + new: parentClone + }); + node.parentNode.parentNode.replaceChild(parentClone, node.parentNode); + } + }); + } + + remove() { + while (this.nodeStack.length) { + let pair = this.nodeStack.pop(); + pair.new.parentNode.replaceChild(pair.old, pair.new); + } + } + + content() { + return document.querySelector(this.opts.contentSelector); + } +} diff --git a/assets/js/helpers/index.js b/assets/js/helpers/index.js new file mode 100644 index 0000000..481f436 --- /dev/null +++ b/assets/js/helpers/index.js @@ -0,0 +1 @@ +export * from './highlight'; diff --git a/assets/js/index.js b/assets/js/index.js new file mode 100644 index 0000000..f193426 --- /dev/null +++ b/assets/js/index.js @@ -0,0 +1,10 @@ +import { newLangController, newSearchController, newToCController } from './controllers'; +import Alpine from 'jslibs/alpinejs/v3/alpinejs/dist/module.esm.js'; + +// Register AlpineJS data controllers. +Alpine.data('searchController', newSearchController); +Alpine.data('tocController', newToCController); +Alpine.data('langController', newLangController); + +// Start AlpineJS. +Alpine.start(); diff --git a/assets/js/slate/app/_lang.js b/assets/js/slate/app/_lang.js deleted file mode 100644 index 745ecba..0000000 --- a/assets/js/slate/app/_lang.js +++ /dev/null @@ -1,167 +0,0 @@ -//= require ../lib/_jquery - -/* -Copyright 2008-2013 Concur Technologies, Inc. - -Licensed under the Apache License, Version 2.0 (the "License"); you may -not use this file except in compliance with the License. You may obtain -a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -License for the specific language governing permissions and limitations -under the License. -*/ -(function (global) { - 'use strict'; - - var languages = []; - - - global.setupLanguages = setupLanguages; - global.activateLanguage = activateLanguage; - - function activateLanguage(language) { - - if (!language) return; - if (language === "") return; - $(".lang-selector a").removeClass('active'); - $(".lang-selector a[data-language-name='" + language + "']").addClass('active'); - // Mod to match Pygments from Hugo: div.highlight > pre code.language-ruby - var codeSelectorPrefix = ".highlight code.language-"; - for (var i=0; i < languages.length; i++) { - $(codeSelectorPrefix + languages[i]).parentsUntil(".highlight").hide(); - $(".lang-specific." + languages[i]).hide(); - } - $(codeSelectorPrefix + language).parentsUntil(".highlight").show(); - $(".lang-specific." + language).parentsUntil(".highlight").show(); - - // scroll to the new location of the position - if ($(window.location.hash).get(0)) { - $(window.location.hash).get(0).scrollIntoView(true); - } - } - - // parseURL and stringifyURL are from https://github.com/sindresorhus/query-string - // MIT licensed - // https://github.com/sindresorhus/query-string/blob/7bee64c16f2da1a326579e96977b9227bf6da9e6/license - function parseURL(str) { - if (typeof str !== 'string') { - return {}; - } - - str = str.trim().replace(/^(\?|#|&)/, ''); - - if (!str) { - return {}; - } - - return str.split('&').reduce(function (ret, param) { - var parts = param.replace(/\+/g, ' ').split('='); - var key = parts[0]; - var val = parts[1]; - - key = decodeURIComponent(key); - // missing `=` should be `null`: - // http://w3.org/TR/2012/WD-url-20120524/#collect-url-parameters - val = val === undefined ? null : decodeURIComponent(val); - - if (!ret.hasOwnProperty(key)) { - ret[key] = val; - } else if (Array.isArray(ret[key])) { - ret[key].push(val); - } else { - ret[key] = [ret[key], val]; - } - - return ret; - }, {}); - }; - - function stringifyURL(obj) { - return obj ? Object.keys(obj).sort().map(function (key) { - var val = obj[key]; - - if (Array.isArray(val)) { - return val.sort().map(function (val2) { - return encodeURIComponent(key) + '=' + encodeURIComponent(val2); - }).join('&'); - } - - return encodeURIComponent(key) + '=' + encodeURIComponent(val); - }).join('&') : ''; - }; - - // gets the language set in the query string - function getLanguageFromQueryString() { - if (location.search.length >= 1) { - var language = parseURL(location.search).language; - if (language) { - return language; - } else if (jQuery.inArray(location.search.substr(1), languages) != -1) { - return location.search.substr(1); - } - } - - return false; - } - - // returns a new query string with the new language in it - function generateNewQueryString(language) { - var url = parseURL(location.search); - if (url.language) { - url.language = language; - return stringifyURL(url); - } - return language; - } - - // if a button is clicked, add the state to the history - function pushURL(language) { - if (!history) { return; } - var hash = window.location.hash; - if (hash) { - hash = hash.replace(/^#+/, ''); - } - history.pushState({}, '', '?' + generateNewQueryString(language) + '#' + hash); - - // save language as next default - localStorage.setItem("language", language); - } - - function setupLanguages(l) { - var defaultLanguage = localStorage.getItem("language"); - - languages = l; - - var presetLanguage = getLanguageFromQueryString(); - if (presetLanguage) { - // the language is in the URL, so use that language! - activateLanguage(presetLanguage); - - localStorage.setItem("language", presetLanguage); - } else if ((defaultLanguage !== null) && (jQuery.inArray(defaultLanguage, languages) != -1)) { - // the language was the last selected one saved in localstorage, so use that language! - activateLanguage(defaultLanguage); - } else { - // no language selected, so use the default - activateLanguage(languages[0]); - } - } - - // if we click on a language tab, activate that language - $(function() { - $(".lang-selector a").on("click", function() { - var language = $(this).data("language-name"); - pushURL(language); - activateLanguage(language); - return false; - }); - window.onpopstate = function() { - activateLanguage(getLanguageFromQueryString()); - }; - }); -})(window); diff --git a/assets/js/slate/app/_search.js b/assets/js/slate/app/_search.js deleted file mode 100644 index da51dbb..0000000 --- a/assets/js/slate/app/_search.js +++ /dev/null @@ -1,103 +0,0 @@ -//= require ../lib/_lunr -//= require ../lib/_jquery -//= require ../lib/_jquery.highlight -; (function () { - 'use strict'; - - var content, searchResults; - var highlightOpts = { element: 'span', className: 'search-highlight' }; - var searchDelay = 0; - var timeoutHandle = 0; - var index; - - $(populate); - $(bind); - - function populate() { - index = lunr(function () { - this.ref('id'); - this.field('title', { boost: 10 }); - this.field('body') - this.pipeline.add(lunr.trimmer, lunr.stopWordFilter); - var that = this; - - $('h1, h2').each(function () { - var title = $(this); - var body = title.nextUntil('h1, h2'); - that.add({ - id: title.prop('id'), - title: title.text(), - body: body.text() - }); - }); - - determineSearchDelay(this); - - }) - } - - - function determineSearchDelay(index) { - if (index._documents.length > 5000) { - searchDelay = 300; - } - } - - function bind() { - content = $('.content'); - searchResults = $('.search-results'); - - $('#input-search').on('keyup', function (e) { - var wait = function () { - return function (executingFunction, waitTime) { - clearTimeout(timeoutHandle); - timeoutHandle = setTimeout(executingFunction, waitTime); - }; - }(); - wait(function () { - search(e); - }, searchDelay); - }); - } - - function search(event) { - - var searchInput = $('#input-search')[0]; - - unhighlight(); - searchResults.addClass('visible'); - - // ESC clears the field - if (event.keyCode === 27) searchInput.value = ''; - - if (searchInput.value) { - var results = index.search(searchInput.value).filter(function (r) { - return r.score > 0.0001; - }); - - if (results.length) { - searchResults.empty(); - $.each(results, function (index, result) { - var elem = document.getElementById(result.ref); - searchResults.append("<li><a href='#" + result.ref + "'>" + $(elem).text() + "</a></li>"); - }); - highlight.call(searchInput); - } else { - searchResults.html('<li></li>'); - $('.search-results li').text('No Results Found for "' + searchInput.value + '"'); - } - } else { - unhighlight(); - searchResults.removeClass('visible'); - } - } - - function highlight() { - if (this.value) content.highlight(this.value, highlightOpts); - } - - function unhighlight() { - content.unhighlight(highlightOpts); - } -})(); - diff --git a/assets/scss/slate/_styles.scss b/assets/scss/slate/_styles.scss new file mode 100644 index 0000000..6729067 --- /dev/null +++ b/assets/scss/slate/_styles.scss @@ -0,0 +1,17 @@ +.content { + // prevent clearing of highlight divs + &>div.highlight { + clear:none; + } + } + + .toc-wrapper .toc-h3 { + padding-left: 50px; + font-size: 12px; + } + + .da-toc-list-h2 { + background-color: $nav-subitem-bg; + font-weight: 500; + } +
\ No newline at end of file diff --git a/assets/scss/slate/_variables.scss b/assets/scss/slate/_variables.scss index ef371cf..a0dd54b 100644 --- a/assets/scss/slate/_variables.scss +++ b/assets/scss/slate/_variables.scss @@ -1,17 +1,5 @@ @import 'docuapi_overrides'; -.content { - // prevent clearing of highlight divs - &>div.highlight { - clear:none; - } -} - -.toc-wrapper .toc-h3 { - padding-left: 50px; - font-size: 12px; -} - // BACKGROUND COLORS //////////////////// $nav-bg: #2E3336 !default; @@ -102,3 +90,8 @@ $search-box-border-color: #666 !default; word-break: break-all; hyphens: auto; } + +// DocuAPI overrides. +//////////////////// +@import 'styles'; + diff --git a/config.toml b/config.toml index ee56fd7..8a82bed 100644 --- a/config.toml +++ b/config.toml @@ -5,15 +5,12 @@ baseURL = "https://example.com/" [module.hugoVersion] min = "0.71.0" [[module.imports]] -path="github.com/jquery/jquery-dist" -[[module.imports.mounts]] -source="dist/jquery.js" -target="assets/js/slate/lib/_jquery.js" +path = "github.com/gohugoio/hugo-mod-jslibs-dist/alpinejs/v3" [[module.imports]] path="github.com/olivernn/lunr.js" [[module.imports.mounts]] source="lunr.js" -target="assets/js/slate/lib/_lunr.js" +target="assets/js/lib/lunr.js" [[module.imports]] path="github.com/slatedocs/slate" [[module.imports.mounts]] @@ -25,6 +22,4 @@ target="static/fonts" [[module.imports.mounts]] source="source/stylesheets" target="assets/scss/slate" -[[module.imports.mounts]] -source="source/javascripts" -target="assets/js/slate" + diff --git a/exampleSite/.gitignore b/exampleSite/.gitignore index 85a1daf..f301b88 100644 --- a/exampleSite/.gitignore +++ b/exampleSite/.gitignore @@ -1 +1,3 @@ -/public
\ No newline at end of file +/public +.hugo_build.lock +/assets/jsconfig.json
\ No newline at end of file diff --git a/exampleSite/go.mod b/exampleSite/go.mod index 6c6d9cf..d1dffea 100644 --- a/exampleSite/go.mod +++ b/exampleSite/go.mod @@ -1,10 +1,10 @@ -module github.com/bep/docuapi +module github.com/bep/docuapi/exampleSite -go 1.12 +go 1.16 require ( github.com/bep/empty-hugo-module v1.0.0 // indirect - github.com/jquery/jquery-dist v0.0.0-20210302171154-e786e3d9707f // indirect + github.com/gohugoio/hugo-mod-jslibs-dist/alpinejs/v3 v3.401.201 // indirect github.com/olivernn/lunr.js v2.3.9+incompatible // indirect github.com/slatedocs/slate v2.9.2+incompatible // indirect ) diff --git a/exampleSite/go.sum b/exampleSite/go.sum index 579a06f..82a169c 100644 --- a/exampleSite/go.sum +++ b/exampleSite/go.sum @@ -1,7 +1,7 @@ github.com/bep/empty-hugo-module v1.0.0 h1:aYc9RWea644CdYjg9zCy8nkVF4KjC3fwhUTvvcXXg8s= github.com/bep/empty-hugo-module v1.0.0/go.mod h1:whohinbSjMoFi/Skivj9kvdPs1tEgzYpZ4rXoQk/0/I= -github.com/jquery/jquery-dist v0.0.0-20210302171154-e786e3d9707f h1:VrcFwwDo/nKErNIKmp//iOGu7DlRkBTeW//hN7tl7SU= -github.com/jquery/jquery-dist v0.0.0-20210302171154-e786e3d9707f/go.mod h1:/lTfttEqFU0GWTaOOMIeNTzLGQ7yTIgyzjtkS/pYIoc= +github.com/gohugoio/hugo-mod-jslibs-dist/alpinejs/v3 v3.401.201 h1:rIBco2i/51nTPbi7pHUvwBwznCddMOsp/9pR2veAPx8= +github.com/gohugoio/hugo-mod-jslibs-dist/alpinejs/v3 v3.401.201/go.mod h1:WWQxcmPs5Xy3xDgi29ipkmZT6NKVb3bsqyCDTY3eYYY= github.com/olivernn/lunr.js v2.3.9+incompatible h1:eH8iBnjlR4mwlYDdNuqy9PCNLjp2bEs6aoNnTSaccx0= github.com/olivernn/lunr.js v2.3.9+incompatible/go.mod h1:yEkQ1DUSMtNsn8n2CqvQXZd0ErWPEG8g9QRmblR+KS8= github.com/slatedocs/slate v2.9.2+incompatible h1:PnIMTR1S7pE6tImIjF6ny9UaRrt6fukM93lwUwJPtjw= diff --git a/exampleSite/resources/_gen/assets/scss/scss/slate/print.css.scss_c14439616ffbc3ae1827507340d6c08b.content b/exampleSite/resources/_gen/assets/scss/scss/slate/print.css.scss_c14439616ffbc3ae1827507340d6c08b.content index d9dc130..404743e 100644 --- a/exampleSite/resources/_gen/assets/scss/scss/slate/print.css.scss_c14439616ffbc3ae1827507340d6c08b.content +++ b/exampleSite/resources/_gen/assets/scss/scss/slate/print.css.scss_c14439616ffbc3ae1827507340d6c08b.content @@ -357,13 +357,6 @@ td, th { padding: 0; } -.content > div.highlight { - clear: none; } - -.toc-wrapper .toc-h3 { - padding-left: 50px; - font-size: 12px; } - body, .content h3, .content h4, .content h2, .content h1 { font-family: "Source Sans Pro", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 14px; @@ -381,6 +374,17 @@ body, .content h3, .content h4, .content h2, .content h1 { word-break: break-all; hyphens: auto; } +.content > div.highlight { + clear: none; } + +.toc-wrapper .toc-h3 { + padding-left: 50px; + font-size: 12px; } + +.da-toc-list-h2 { + background-color: #1E2224; + font-weight: 500; } + @font-face { font-family: 'slateeee'; src: url("../fonts/slate.eot?-syv14m"); diff --git a/exampleSite/resources/_gen/assets/scss/scss/slate/screen.css.scss_d18af36970f1f09b308ef20ee65e3a03.content b/exampleSite/resources/_gen/assets/scss/scss/slate/screen.css.scss_d18af36970f1f09b308ef20ee65e3a03.content index a77d3a3..1052cc6 100644 --- a/exampleSite/resources/_gen/assets/scss/scss/slate/screen.css.scss_d18af36970f1f09b308ef20ee65e3a03.content +++ b/exampleSite/resources/_gen/assets/scss/scss/slate/screen.css.scss_d18af36970f1f09b308ef20ee65e3a03.content @@ -357,13 +357,6 @@ td, th { padding: 0; } -.content > div.highlight { - clear: none; } - -.toc-wrapper .toc-h3 { - padding-left: 50px; - font-size: 12px; } - html, body, .content h3, .content h4, .content h5, .content h6, .content h2, .content h1 { font-family: "Source Sans Pro", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 14px; @@ -381,6 +374,17 @@ html, body, .content h3, .content h4, .content h5, .content h6, .content h2, .co word-break: break-all; hyphens: auto; } +.content > div.highlight { + clear: none; } + +.toc-wrapper .toc-h3 { + padding-left: 50px; + font-size: 12px; } + +.da-toc-list-h2 { + background-color: #1E2224; + font-weight: 500; } + @font-face { font-family: 'slateeee'; src: url("../fonts/slate.eot?-syv14m"); @@ -1,9 +1,9 @@ -module github.com/bep/docuapi +module github.com/bep/docuapi/v2 -go 1.12 +go 1.16 require ( - github.com/jquery/jquery-dist v0.0.0-20210302171154-e786e3d9707f // indirect + github.com/gohugoio/hugo-mod-jslibs-dist/alpinejs/v3 v3.401.201 // indirect github.com/olivernn/lunr.js v2.3.9+incompatible // indirect github.com/slatedocs/slate v2.9.2+incompatible // indirect ) @@ -1,5 +1,5 @@ -github.com/jquery/jquery-dist v0.0.0-20210302171154-e786e3d9707f h1:VrcFwwDo/nKErNIKmp//iOGu7DlRkBTeW//hN7tl7SU= -github.com/jquery/jquery-dist v0.0.0-20210302171154-e786e3d9707f/go.mod h1:/lTfttEqFU0GWTaOOMIeNTzLGQ7yTIgyzjtkS/pYIoc= +github.com/gohugoio/hugo-mod-jslibs-dist/alpinejs/v3 v3.401.201 h1:rIBco2i/51nTPbi7pHUvwBwznCddMOsp/9pR2veAPx8= +github.com/gohugoio/hugo-mod-jslibs-dist/alpinejs/v3 v3.401.201/go.mod h1:WWQxcmPs5Xy3xDgi29ipkmZT6NKVb3bsqyCDTY3eYYY= github.com/olivernn/lunr.js v2.3.9+incompatible h1:eH8iBnjlR4mwlYDdNuqy9PCNLjp2bEs6aoNnTSaccx0= github.com/olivernn/lunr.js v2.3.9+incompatible/go.mod h1:yEkQ1DUSMtNsn8n2CqvQXZd0ErWPEG8g9QRmblR+KS8= github.com/slatedocs/slate v2.9.2+incompatible h1:PnIMTR1S7pE6tImIjF6ny9UaRrt6fukM93lwUwJPtjw= diff --git a/layouts/_default/baseof.html b/layouts/_default/baseof.html index fdde37c..61349ce 100644 --- a/layouts/_default/baseof.html +++ b/layouts/_default/baseof.html @@ -1,69 +1,75 @@ <!doctype html> <html lang="{{ .Lang | default "en" }}"> -<head> + <head> <meta charset="utf-8"> <meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"> - <title>{{ .Title }}</title> + <title> + {{ .Title }} + </title> {{ partial "styles.html" . }} {{ partial "js.html" . }} {{ partial "hook_head_end.html" . }} -</head> -<body class="index" data-languages="{{ with .Site.Params.language_tabs }}[{{ range $i,$e := . }}{{- if $i -}}, {{ end -}}{{ printf " %q " $e.key }}{{end}}]{{ end }}"> - <a href="#" id="nav-button"> - <span> + </head> + <body class="index" x-data="{ navOpen: false }"> + <a href="#" id="nav-button" @click="navOpen = !navOpen" :class="{'open': navOpen }"> + <span> NAV <img src='{{ relURL "images/navbar.png" }}'/> </span> </a> - <div class="toc-wrapper"> - {{ partial "hook_left_sidebar_start.html" . }} - {{ partial "hook_left_sidebar_logo.html" . }} - {{ with .Site.Params.language_tabs }} - <div class="lang-selector"> - {{ range . }} - <a href="#" data-language-name="{{ .key }}">{{ .name }}</a> - {{ end }} - </div> - {{ end }} - {{ if .Site.Params.search }} - <div class="search"> - <input type="search" class="search" id="input-search" placeholder='{{ T "search" . }}'> + <div class="toc-wrapper" :class="{'open': navOpen }"> + {{ partial "hook_left_sidebar_start.html" . }} + {{ partial "hook_left_sidebar_logo.html" . }} + {{ if .Site.Params.search }} + <div class="search" x-data="searchController"> + <input x-model.debounce.100ms="query" type="search" class="search" id="input-search" placeholder='{{ T "search" . }}'> + <ul class="search-results visible" x-show="results.length > 0" x-transition.duration.700ms > + <template x-for="item in results"> + <li> + <a x-text="item.title"></a> + </li> + </template> + </ul> </div> - <ul class="search-results"></ul> - {{ end }} - {{ block "toc" . }}{{ end }} - {{ if .IsTranslated }} - <ul class="toc-footer"> - <li class="toc-h1">{{ T "translations" (len .Translations ) }}</li> - {{ partial "translations.html" . }} - </ul> - - {{ end }} - {{ with .Site.Params.toc_footers }} + {{ end }} + {{ block "toc" . }}{{ end }} + {{ if .IsTranslated }} + <ul class="toc-footer"> + <li class="toc-h1"> + {{ T "translations" (len .Translations ) }} + </li> + {{ partial "translations.html" . }} + </ul> + {{ end }} + {{ with .Site.Params.toc_footers }} <ul class="toc-footer"> - {{ range . }} - <li>{{ . | markdownify }}</li> - {{ end}} + {{ range . }} + <li> + {{ . | markdownify }} + </li> + {{ end}} </ul> - {{ end}} - {{ partial "hook_left_sidebar_end.html" . }} + {{ end}} + {{ partial "hook_left_sidebar_end.html" . }} </div> <div class="page-wrapper"> - <div class="dark-box"></div> - <div class="content"> - {{block "main" .}}This is the main content.{{end}} - </div> - <div class="dark-box"> - {{ with .Site.Params.language_tabs }} - <div class="lang-selector"> - {{ range . }} - <a href="#" data-language-name="{{ .key }}">{{ .name }}</a> - {{ end }} - </div> - {{ end }} - </div> + <div class="dark-box"></div> + <div class="content"> + {{block "main" .}} + This is the main content. + {{end}} + </div> + <div class="dark-box"> + {{ with .Site.Params.language_tabs }} + <div class="lang-selector" x-data="langController" x-init="initLangs({{ . | jsonify }})"> + <template x-for="(tab, index) in tabs"> + <a x-text="tab.name" :class="{ 'active': tab.active }" @click="changeLanguage(index)"></a> + </template> + </div> + {{ end }} + </div> </div> {{ partial "hook_body_end.html" . }} -</body> + </body> </html> diff --git a/layouts/_default/list.html b/layouts/_default/list.html index ee32bbe..10871b5 100644 --- a/layouts/_default/list.html +++ b/layouts/_default/list.html @@ -8,45 +8,34 @@ {{ end }} {{ define "toc" }} - <ul id="toc" class="toc-list-h1"> - {{ $maxDepth := 0 }} - {{ with $.Site.Params.maxMenuDepth }} - {{ $maxDepth = . }} - {{ else }} - {{ $maxDepth = 2 }} - {{ end }} - {{ $headers := slice }} - {{ with .Site.RegularPages }} - {{ $headers = partial "funcs/toc_from_pages" . }} - {{ end }} - {{ range $headers }} + {{ $headers := slice }} + {{ with .Site.RegularPages }} + {{ $headers = partial "funcs/toc_from_pages" . }} + {{ end }} + <ul id="toc" class="toc-list-h1" x-data="tocController" x-init="load({{ $headers | jsonify }})" @scroll.window="onScroll()"> + {{ $maxDepth := $.Site.Params.maxMenuDepth | default 2 }} + <template x-for="row in rows"> <li> - <a href="#{{ .id }}" class="toc-h{{ .level }} toc-link" data-title="{{ .title }}"> - {{ .title }} - </a> - {{ if and (ge $maxDepth 2) .sub }} - <ul class="toc-list-h2"> - {{ range .sub }} + <a x-text="row.title" @click="click(row)" :href="`#${row.id}`" class="toc-link" x-bind="rowClass(row)"></a> + {{ if (ge $maxDepth 2) }} + <ul x-show="row.open" x-bind="transitions()" class="da-toc-list-h2"> + <template x-for="row in row.sub"> <li> - <a href="#{{ .id }}" class="toc-h{{ .level }} toc-link" data-title="{{ .title }}"> - {{ .title }} - </a> - {{ if and (ge $maxDepth 3) .sub }} - <ul class="toc-list-h3"> - {{ range .sub }} + <a x-text="row.title" @click="click(row)" :href="`#${row.id}`" class="toc-link" x-bind="rowClass(row)"></a> + {{ if (ge $maxDepth 3) }} + <ul x-show="row.open" x-bind="transitions()" class="toc-list-h3"> + <template x-for="row in row.sub"> <li> - <a href="#{{ .id }}" class="toc-h{{ .level }} toc-link" data-title="{{ .title }}"> - {{ .title }} - </a> + <a x-text="row.title" @click="click(row)" :href="`#${row.id}`" class="toc-link" x-bind="rowClass(row)"></a> </li> - {{ end }} + </template> </ul> {{ end }} </li> - {{ end }} + </template> </ul> {{ end }} </li> - {{ end }} + </template> </ul> {{ end }} diff --git a/layouts/partials/funcs/extract_js_requirements.html b/layouts/partials/funcs/extract_js_requirements.html deleted file mode 100644 index 77c852d..0000000 --- a/layouts/partials/funcs/extract_js_requirements.html +++ /dev/null @@ -1,20 +0,0 @@ -{{ $req := findRE "//= require (\\S*)" .resource.Content }} -{{ $dir := path.Dir .resource.Name }} -{{ $imports := slice }} -{{ range $req }} - {{ $imp := strings.TrimPrefix "//= require" . }} - {{ $imp = trim $imp " " }} - {{ $imp = printf "/%s.js" (path.Join $dir $imp) }} - {{ if not ($.visited.Get $imp) }} - {{ $.visited.Set $imp true }} - {{ $nested := resources.Get $imp }} - {{ if $nested }} - {{ $imports = $imports | append (partial "funcs/extract_js_requirements.html" (dict "resource" $nested "visited" $.visited )) }} - {{ else }} - {{ errorf "Lib not found: %q" . }} - {{ end }}} - {{ end }} -{{ $imports = $imports | append $imp }} -{{ end }} -{{ $imports = $imports | append .resource.RelPermalink }} -{{ return $imports }} diff --git a/layouts/partials/funcs/get_and_concat.html b/layouts/partials/funcs/get_and_concat.html deleted file mode 100644 index 5dfacb5..0000000 --- a/layouts/partials/funcs/get_and_concat.html +++ /dev/null @@ -1,10 +0,0 @@ -{{ if not .target }}{{ errorf "Missing target"}}{{ end }} -{{ if not .imports }}{{ errorf "Missing imports"}}{{ end }} -{{ $resources := slice }} -{{ range .imports }} -{{ $resource := resources.Get . }} -{{ if $resource }} -{{ $resources = $resources | append $resource }} -{{ end }} -{{ end }} -{{ return ($resources | resources.Concat .target) }}
\ No newline at end of file diff --git a/layouts/partials/js.html b/layouts/partials/js.html index ae953b4..1b001d2 100644 --- a/layouts/partials/js.html +++ b/layouts/partials/js.html @@ -1,16 +1,9 @@ -{{ $isDev := ne hugo.Environment "production" }} -{{ $allJS := resources.Get "js/slate/all.js" }} -{{ $allNoSearchJS := resources.Get "js/slate/all_nosearch.js" }} -{{ $importsAll := partial "funcs/extract_js_requirements.html" (dict "resource" $allJS "visited" newScratch ) | uniq }} -{{ $importsAllNoSearch := partial "funcs/extract_js_requirements.html" (dict "resource" $allNoSearchJS "visited" newScratch ) | uniq }} -{{ $jsAll := partialCached "funcs/get_and_concat.html" (dict "imports" $importsAll "target" "js/all.js" ) "all" }} -{{ $jsAllNoSearch := partialCached "funcs/get_and_concat.html" (dict "imports" $importsAllNoSearch "target" "js/all_nosearch.js" ) "no search"}} -{{ if not $isDev }} -{{ $jsAll = $jsAll | minify | fingerprint }} -{{ $jsAllNoSearch = $jsAllNoSearch | minify | fingerprint }} -{{ end }} -{{ if .Param "search" }} -<script src='{{ $jsAll.RelPermalink }}'{{ if not $isDev }} integrity="{{ $jsAll.Data.Integrity }}"{{ end }}></script> -{{ else }} -<script src='{{ $jsAllNoSearch.RelPermalink }}'{{ if not $isDev }} integrity="{{ $jsAllNoSearch.Data.Integrity }}"{{ end }}></script> -{{ end }}
\ No newline at end of file +{{- $js := resources.Get "js/index.js" -}} +{{ $params := (dict "search_config" site.Params.search_config "is_production" hugo.IsProduction ) }} +{{ $sourceMap := cond hugo.IsProduction "" "inline" }} +{{ $opts := dict "sourceMap" $sourceMap "minify" hugo.IsProduction "target" "es2018" "params" $params }} +{{ $js = $js | js.Build $opts }} +{{ if hugo.IsProduction }} + {{ $js = $js | fingerprint }} +{{ end }} +<script src="{{ $js.RelPermalink }}" {{ if hugo.IsProduction }}integrity="{{ $js.Data.Integrity }}"{{ end }} defer></script> diff --git a/netlify.toml b/netlify.toml index 493a805..7135ef7 100644 --- a/netlify.toml +++ b/netlify.toml @@ -3,18 +3,18 @@ publish = "exampleSite/public" command = "hugo --gc -s exampleSite --minify" [context.production.environment] -HUGO_VERSION = "0.82.0" +HUGO_VERSION = "0.88.1" [context.deploy-preview] -command = "hugo -s exampleSite -D -F -b $DEPLOY_PRIME_URL" +command = "hugo -s exampleSite --minify -D -F -b $DEPLOY_PRIME_URL" [context.deploy-preview.environment] -HUGO_VERSION = "0.82.0" +HUGO_VERSION = "0.88.1" [context.branch-deploy] -command = "hugo -s exampleSite --gc -b $DEPLOY_PRIME_URL" +command = "hugo -s exampleSite --minify --gc -b $DEPLOY_PRIME_URL" [context.branch-deploy.environment] -HUGO_VERSION = "0.82.0" +HUGO_VERSION = "0.88.1" diff --git a/resources/_gen/assets/scss/scss/slate/print.css.scss_c14439616ffbc3ae1827507340d6c08b.content b/resources/_gen/assets/scss/scss/slate/print.css.scss_c14439616ffbc3ae1827507340d6c08b.content index c29f768..3504b18 100644 --- a/resources/_gen/assets/scss/scss/slate/print.css.scss_c14439616ffbc3ae1827507340d6c08b.content +++ b/resources/_gen/assets/scss/scss/slate/print.css.scss_c14439616ffbc3ae1827507340d6c08b.content @@ -359,12 +359,16 @@ th { .content > div.highlight { clear: none; } -.content h1, .content h2, .content h3, .content h4, body { +.toc-wrapper .toc-h3 { + padding-left: 50px; + font-size: 12px; } + +body, .content h3, .content h4, .content h2, .content h1 { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 14px; font-weight: 400; } -.content h1, .content h2, .content h3, .content h4 { +.content h3, .content h4, .content h2, .content h1 { font-weight: 700; } .content pre, .content code { @@ -383,7 +387,7 @@ th { font-weight: normal; font-style: normal; } -.content aside.warning:before, .content aside.notice:before, .content aside.success:before { +.content aside.success:before, .content aside.notice:before, .content aside.warning:before { font-family: 'slateeee'; speak: none; font-style: normal; @@ -483,4 +487,8 @@ under the License. padding-right: 0.5em; font-size: 14px; } +@media print { + .copy-clipboard { + display: none; } } + /*# sourceMappingURL=print.css.map */
\ No newline at end of file diff --git a/resources/_gen/assets/scss/scss/slate/screen.css.scss_d18af36970f1f09b308ef20ee65e3a03.content b/resources/_gen/assets/scss/scss/slate/screen.css.scss_d18af36970f1f09b308ef20ee65e3a03.content index 32139d1..fd8784f 100644 --- a/resources/_gen/assets/scss/scss/slate/screen.css.scss_d18af36970f1f09b308ef20ee65e3a03.content +++ b/resources/_gen/assets/scss/scss/slate/screen.css.scss_d18af36970f1f09b308ef20ee65e3a03.content @@ -359,15 +359,19 @@ th { .content > div.highlight { clear: none; } -.content h1, .content h2, .content h3, .content h4, .content h5, .content h6, html, body { +.toc-wrapper .toc-h3 { + padding-left: 50px; + font-size: 12px; } + +html, body, .content h3, .content h4, .content h5, .content h6, .content h2, .content h1 { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 14px; font-weight: 400; } -.content h1, .content h2, .content h3, .content h4, .content h5, .content h6 { +.content h3, .content h4, .content h5, .content h6, .content h2, .content h1 { font-weight: 700; } -.content code, .content pre { +.content pre, .content code { font-family: Consolas, Menlo, Monaco, "Lucida Console", "Liberation Mono", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Courier New", monospace, serif; font-size: 12px; line-height: 1.5; } @@ -383,7 +387,7 @@ th { font-weight: normal; font-style: normal; } -.content aside.warning:before, .content aside.notice:before, .content aside.success:before, .toc-wrapper > .search:before { +.toc-wrapper > .search:before, .content aside.success:before, .content aside.notice:before, .content aside.warning:before { font-family: 'slateeee'; speak: none; font-style: normal; @@ -595,12 +599,13 @@ html, body { border-bottom: 5px solid #2E3336; } .lang-selector { + display: flex; background-color: #1E2224; width: 100%; - font-weight: bold; } + font-weight: bold; + overflow-x: auto; } .lang-selector a { - display: block; - float: left; + display: inline; color: #fff; text-decoration: none; padding: 0 10px; @@ -726,6 +731,9 @@ html, body { border: 1px solid #F7E633; background: linear-gradient(to top left, #F7E633 0%, #F1D32F 100%); } +.content > div.highlight { + clear: none; } + .content pre, .content blockquote { background-color: #1E2224; color: #fff; @@ -785,4 +793,15 @@ html, body { .highlight, .highlight .w { background-color: #1E2224; } +.copy-clipboard { + float: right; + fill: #9DAAB6; + cursor: pointer; + opacity: 0.4; + height: 18px; + width: 18px; } + +.copy-clipboard:hover { + opacity: 0.8; } + /*# sourceMappingURL=screen.css.map */
\ No newline at end of file |