From e004f35404616cf9986130060ca5d198f4c5b291 Mon Sep 17 00:00:00 2001 From: a Date: Sun, 16 Oct 2022 17:15:34 -0500 Subject: [PATCH] feature bringup --- assets/scripts/search.js | 225 ++++++++++++++++++ .../styles/common/{page.scss => content.scss} | 68 ++++-- assets/styles/components/breadcrumbs.scss | 17 ++ assets/styles/components/header-menu.scss | 5 - .../{docs-menu.scss => nav-docs.scss} | 13 +- assets/styles/components/nav-header.scss | 16 ++ assets/styles/components/nav-section.scss | 37 +++ .../styles/components/single/page-header.scss | 20 ++ assets/styles/components/site-footer.scss | 11 +- assets/styles/components/site-header.scss | 5 +- .../styles/components/table-of-contents.scss | 27 +++ assets/styles/features/headings.scss | 74 ++++++ assets/styles/features/search.scss | 48 ++++ .../styles/features/syntax-highlighting.scss | 110 +++++++++ assets/styles/print.scss | 11 +- assets/styles/screen.scss | 15 +- assets/styles/screen/layout.scss | 36 +-- assets/styles/screen/links.scss | 19 +- layouts/_default/_markup/render-heading.html | 6 + layouts/_default/baseof.html | 49 ++-- layouts/_default/single.html | 14 +- layouts/index.html | 2 +- layouts/index.json | 8 + layouts/partials/nav-docs.html | 10 +- layouts/partials/nav-footer.html | 2 +- layouts/partials/nav-header.html | 30 +-- layouts/partials/nav-section.html | 10 + layouts/partials/page-footer.html | 4 + layouts/partials/search/search-form.html | 5 + layouts/partials/search/search-index.html | 3 + layouts/partials/seo.html | 6 +- layouts/partials/site-footer.html | 1 + layouts/partials/site-header.html | 1 + layouts/search/list.html | 21 ++ 34 files changed, 816 insertions(+), 113 deletions(-) create mode 100644 assets/scripts/search.js rename assets/styles/common/{page.scss => content.scss} (78%) create mode 100644 assets/styles/components/breadcrumbs.scss delete mode 100644 assets/styles/components/header-menu.scss rename assets/styles/components/{docs-menu.scss => nav-docs.scss} (82%) create mode 100644 assets/styles/components/nav-header.scss create mode 100644 assets/styles/components/nav-section.scss create mode 100644 assets/styles/components/single/page-header.scss create mode 100644 assets/styles/components/table-of-contents.scss create mode 100644 assets/styles/features/headings.scss create mode 100644 assets/styles/features/search.scss create mode 100644 assets/styles/features/syntax-highlighting.scss create mode 100644 layouts/_default/_markup/render-heading.html create mode 100644 layouts/index.json create mode 100644 layouts/partials/nav-section.html create mode 100644 layouts/partials/page-footer.html create mode 100644 layouts/partials/search/search-form.html create mode 100644 layouts/partials/search/search-index.html create mode 100644 layouts/search/list.html diff --git a/assets/scripts/search.js b/assets/scripts/search.js new file mode 100644 index 0000000..e8dc3ef --- /dev/null +++ b/assets/scripts/search.js @@ -0,0 +1,225 @@ +/* +tutorials used: +- https://aaronluna.dev/blog/add-search-to-static-site-lunrjs-hugo-vanillajs/#codepen-with-final-code +- https://victoria.dev/blog/add-search-to-hugo-static-sites-with-lunr/ +*/ + +let pagesIndex, searchIndex +const MAX_SUMMARY_LENGTH = 30 +const SENTENCE_BOUNDARY_REGEX = /\b\.\s/gm +const WORD_REGEX = /\b(\w*)[\W|\s|\b]?/gm + +async function initSearch() { + try { + const response = await fetch("/index.json"); + pagesIndex = await response.json(); + searchIndex = lunr(function () { + this.field("title"); + this.field("content"); + this.ref("href"); + pagesIndex.forEach((page) => this.add(page)); + }); + } catch (e) { + console.log(e); + } + console.log("Search index initialized") + // Get the query parameter(s) + const params = new URLSearchParams(window.location.search) + const query = params.get('query') + + // Perform a search if there is a query + if (query) { + // Retain the search input in the form when displaying results + document.getElementById('search-input').setAttribute('value', query) + + // Update the list with results + console.log("search performed") + let results = searchSite(query) + renderSearchResults(query, results) + } +} + +initSearch(); + +function searchSite(query) { + const originalQuery = query; + query = getLunrSearchQuery(query); + let results = getSearchResults(query); + return results.length + ? results + : query !== originalQuery + ? getSearchResults(originalQuery) + : []; +} + +function getLunrSearchQuery(query) { + const searchTerms = query.split(" "); + if (searchTerms.length === 1) { + return query; + } + query = ""; + for (const term of searchTerms) { + query += `+${term} `; + } + return query.trim(); +} + +function getSearchResults(query) { + return searchIndex.search(query).flatMap((hit) => { + if (hit.ref == "undefined") return []; + let pageMatch = pagesIndex.filter((page) => page.href === hit.ref)[0]; + pageMatch.score = hit.score; + return [pageMatch]; + }); +} + +function renderSearchResults(query, results) { + clearSearchResults(); + updateSearchResults(query, results); +} + +function clearSearchResults() { + const results = document.querySelector("#search-results"); + while (results.firstChild) results.removeChild(results.firstChild); +} + +function updateSearchResults(query, results) { + document.getElementById("results-query").innerHTML = query; + document.querySelector("#search-results").innerHTML = results + .map( + (hit) => ` +
  • + ${createTitleBlurb(query, hit.title)} +

    ${createSearchResultBlurb(query, hit.content)}

    +
  • + ` + ) + .join(""); + const searchResultListItems = document.querySelectorAll("#search-results li"); + document.getElementById("results-count").innerHTML = searchResultListItems.length; + document.getElementById("results-count-text").innerHTML = searchResultListItems.length === 1 ? "result" : "results"; + // searchResultListItems.forEach( + // (li) => (li.firstElementChild.style.color = getColorForSearchResult(li.dataset.score)) + // ); +} + +function createTitleBlurb(query, title) { + const searchQueryRegex = new RegExp(createQueryStringRegex(query), "gmi"); + return title.replace( + searchQueryRegex, + "$&" + ) +} + +function createSearchResultBlurb(query, pageContent) { + const searchQueryRegex = new RegExp(createQueryStringRegex(query), "gmi"); + const searchQueryHits = Array.from( + pageContent.matchAll(searchQueryRegex), + (m) => m.index + ); + const sentenceBoundaries = Array.from( + pageContent.matchAll(SENTENCE_BOUNDARY_REGEX), + (m) => m.index + ); + let searchResultText = ""; + let lastEndOfSentence = 0; + for (const hitLocation of searchQueryHits) { + if (hitLocation > lastEndOfSentence) { + for (let i = 0; i < sentenceBoundaries.length; i++) { + if (sentenceBoundaries[i] > hitLocation) { + const startOfSentence = i > 0 ? sentenceBoundaries[i - 1] + 1 : 0; + const endOfSentence = sentenceBoundaries[i]; + lastEndOfSentence = endOfSentence; + parsedSentence = pageContent.slice(startOfSentence, endOfSentence).trim(); + searchResultText += `${parsedSentence} ... `; + break; + } + } + } + const searchResultWords = tokenize(searchResultText); + const pageBreakers = searchResultWords.filter((word) => word.length > 50); + if (pageBreakers.length > 0) { + searchResultText = fixPageBreakers(searchResultText, pageBreakers); + } + if (searchResultWords.length >= MAX_SUMMARY_LENGTH) break; + } + return ellipsize(searchResultText, MAX_SUMMARY_LENGTH).replace( + searchQueryRegex, + "$&" + ); +} + +function createQueryStringRegex(query) { + const searchTerms = query.split(" "); + if (searchTerms.length == 1) { + return query; + } + query = ""; + for (const term of searchTerms) { + query += `${term}|`; + } + query = query.slice(0, -1); + return `(${query})`; +} + +function tokenize(input) { + const wordMatches = Array.from(input.matchAll(WORD_REGEX), (m) => m); + return wordMatches.map((m) => ({ + word: m[0], + start: m.index, + end: m.index + m[0].length, + length: m[0].length, + })); +} + +function fixPageBreakers(input, largeWords) { + largeWords.forEach((word) => { + const chunked = chunkify(word.word, 20); + input = input.replace(word.word, chunked); + }); + return input; +} + +function chunkify(input, chunkSize) { + let output = ""; + let totalChunks = (input.length / chunkSize) | 0; + let lastChunkIsUneven = input.length % chunkSize > 0; + if (lastChunkIsUneven) { + totalChunks += 1; + } + for (let i = 0; i < totalChunks; i++) { + let start = i * chunkSize; + let end = start + chunkSize; + if (lastChunkIsUneven && i === totalChunks - 1) { + end = input.length; + } + output += input.slice(start, end) + " "; + } + return output; +} + +function ellipsize(input, maxLength) { + const words = tokenize(input); + if (words.length <= maxLength) { + return input; + } + return input.slice(0, words[maxLength].end) + "..."; +} + +if (!String.prototype.matchAll) { + String.prototype.matchAll = function (regex) { + "use strict"; + function ensureFlag(flags, flag) { + return flags.includes(flag) ? flags : flags + flag; + } + function* matchAll(str, regex) { + const localCopy = new RegExp(regex, ensureFlag(regex.flags, "g")); + let match; + while ((match = localCopy.exec(str))) { + match.index = localCopy.lastIndex - match[0].length; + yield match; + } + } + return matchAll(this, regex); + }; +} \ No newline at end of file diff --git a/assets/styles/common/page.scss b/assets/styles/common/content.scss similarity index 78% rename from assets/styles/common/page.scss rename to assets/styles/common/content.scss index b51ffe8..6a9b3a1 100644 --- a/assets/styles/common/page.scss +++ b/assets/styles/common/content.scss @@ -1,4 +1,4 @@ -.page { +.content { /* text */ h1 {font-size: 1.8em} h2 {font-size: 1.6em} @@ -15,6 +15,7 @@ p { line-height: 2; margin-bottom: 1em; + max-width: 80ch; } a { word-wrap: break-word; @@ -90,15 +91,36 @@ } pre { font-family: monospace; - background: #333; - color: white; + background: var(--ui-overlay); + color: var(--ui-overlay-text); padding: 1em; line-height: 1.4; - overflow-x: scroll; + overflow-x: auto; + white-space: pre; + display: grid; + tab-size: 3; margin-bottom: 1em; } code { font-family: monospace; + background: var(--ui-overlay); + color: var(--ui-overlay-text); + padding: 0.25rem; + } + :not(.highlight) > pre { + line-height: 1.5; + background: var(--ui-overlay); + padding: 1em; + } + pre code { + background: inherit; + padding: 0; + } + pre code > span { + padding: 0 1em; + } + .highlight pre { + padding: 1em 0; } /* figures */ figure { @@ -162,25 +184,25 @@ content: ']'; } } - /* toc */ - .toc-title { - margin-bottom: 0.5em; - font-weight: 900; - text-transform: uppercase; - color: var(--ui-text-muted); - } - #TableOfContents { - ul { - list-style: none; - margin: 0; - } - li { - margin: 0; - line-height: 1.5; - } - li > ul { /* indent subheadings */ - margin: 0; - margin-left: 1em; + /* the actual footnotes section */ + .footnotes { + hr { + display: flex; + align-items: center; + border: 0; + &:before { + content: 'Footnotes'; + color: var(--ui-text); + text-transform: uppercase; + font-weight: 900; + font-size: 0.8em; + } + &:after { + content: ''; + width: 100%; + margin-left: 1rem; + border-bottom: 1px solid var(--ui-text-muted); + } } } } \ No newline at end of file diff --git a/assets/styles/components/breadcrumbs.scss b/assets/styles/components/breadcrumbs.scss new file mode 100644 index 0000000..cb64a3a --- /dev/null +++ b/assets/styles/components/breadcrumbs.scss @@ -0,0 +1,17 @@ +.breadcrumbs { + display: flex; + flex-flow: row wrap; + li:not(:first-child) { + margin-left: 1rem; + margin-bottom: 1rem; + } + li::marker { + content: "> "; + } + li:first-child::marker { + content: ""; + } + li:first-child { + margin-left: 0; + } +} \ No newline at end of file diff --git a/assets/styles/components/header-menu.scss b/assets/styles/components/header-menu.scss deleted file mode 100644 index c567007..0000000 --- a/assets/styles/components/header-menu.scss +++ /dev/null @@ -1,5 +0,0 @@ -.header-nav { - display: flex; - flex-flow: column; - justify-content: center; -} \ No newline at end of file diff --git a/assets/styles/components/docs-menu.scss b/assets/styles/components/nav-docs.scss similarity index 82% rename from assets/styles/components/docs-menu.scss rename to assets/styles/components/nav-docs.scss index d21c7da..91a5104 100644 --- a/assets/styles/components/docs-menu.scss +++ b/assets/styles/components/nav-docs.scss @@ -23,13 +23,22 @@ margin-top: 1em; > li { margin-bottom: 1em; + > a { + display: block; + margin-bottom: 1rem; + } } } - li {line-height: 2} .sub-menu { margin-left: 1em; + display: flex; + flex-flow: column; + gap: 0.5rem; + li { + line-height: 1.5; + } li::marker { - content: '⟣ '; + content: '→ '; } .sub-menu li::marker { content: '↳ '; diff --git a/assets/styles/components/nav-header.scss b/assets/styles/components/nav-header.scss new file mode 100644 index 0000000..4ec3657 --- /dev/null +++ b/assets/styles/components/nav-header.scss @@ -0,0 +1,16 @@ +.header-nav { + display: flex; + flex-flow: row wrap; + justify-content: center; + align-items: center; + .menu { + display: flex; + flex-flow: row wrap; + gap: 1em; + a { + display: flex; + align-items: center; + gap: 0.5em; + } + } +} \ No newline at end of file diff --git a/assets/styles/components/nav-section.scss b/assets/styles/components/nav-section.scss new file mode 100644 index 0000000..9923799 --- /dev/null +++ b/assets/styles/components/nav-section.scss @@ -0,0 +1,37 @@ +.section-nav { + .container { + display: grid; + grid-gap: 1em; + } + a { + border-radius: 0.25rem; + display: flex; + padding: 1em; + gap: 1em; + text-decoration: none; + background: var(--ui-overlay); + color: var(--ui-overlay-text); + &:focus { + padding: 1em; + border: none; + } + } + .previous { + justify-content: start; + } + .arrow { + text-decoration: none; + color: inherit; + display: grid; + place-items: center; + font-size: 2em; + } + @media (min-width: 30rem) { + .container { + grid-template-columns: 1fr 1fr; + } + .next { + grid-column: 2; + } + } +} \ No newline at end of file diff --git a/assets/styles/components/single/page-header.scss b/assets/styles/components/single/page-header.scss new file mode 100644 index 0000000..0cecb33 --- /dev/null +++ b/assets/styles/components/single/page-header.scss @@ -0,0 +1,20 @@ +.page { + .page-title { + font-size: 2em; + margin-bottom: 1rem; + } + .page-summary { + line-height: 1.5; + max-width: 80ch; + } + .lastmod { + margin-top: 1rem; + line-height: 1.5; + color: var(--ui-text-muted); + } + .language-list { + display: flex; + flex-flow: wrap; + list-style: none; + } +} \ No newline at end of file diff --git a/assets/styles/components/site-footer.scss b/assets/styles/components/site-footer.scss index 7d45f7d..3c31e37 100644 --- a/assets/styles/components/site-footer.scss +++ b/assets/styles/components/site-footer.scss @@ -1,11 +1,18 @@ .site-footer { - height: var(--footer-height); display: flex; align-items: center; + padding: 1em 0; } .site-footer hr {display: none;} .site-footer .container { display: flex; justify-content: space-between; + flex-flow: row wrap; + gap: 1em; } -.breadcrumbs {display: flex; flex-flow: row wrap;} \ No newline at end of file + +.footer-nav .menu { + display: flex; + flex-flow: row wrap; + gap: 1em; +} \ No newline at end of file diff --git a/assets/styles/components/site-header.scss b/assets/styles/components/site-header.scss index aaa0772..f5b04f7 100644 --- a/assets/styles/components/site-header.scss +++ b/assets/styles/components/site-header.scss @@ -3,7 +3,7 @@ flex-flow: row; align-items: center; gap: 1em; - padding: 4px; + text-decoration: none; } .site-icon { height: 2em; @@ -24,10 +24,11 @@ .site-header {padding: 1em 0;} .site-header a { - text-decoration: none; + font-weight: 500; } .site-header .container { display: flex; flex-flow: row wrap; justify-content: space-between; + gap: 1em; } \ No newline at end of file diff --git a/assets/styles/components/table-of-contents.scss b/assets/styles/components/table-of-contents.scss new file mode 100644 index 0000000..1f7ae19 --- /dev/null +++ b/assets/styles/components/table-of-contents.scss @@ -0,0 +1,27 @@ +.toc-title { + margin-bottom: 0.5em; + font-weight: 900; + text-transform: uppercase; + color: var(--ui-text-muted); +} +#TableOfContents { + ul { + list-style: none; + margin: 0; + } + li { + margin: 0; + line-height: 1.5; + } + li > ul { /* indent subheadings */ + margin: 0; + margin-left: 1em; + } + ol { + list-style: none; + margin: 0; + } + li > ol { + margin-left: 1em; + } +} \ No newline at end of file diff --git a/assets/styles/features/headings.scss b/assets/styles/features/headings.scss new file mode 100644 index 0000000..336910e --- /dev/null +++ b/assets/styles/features/headings.scss @@ -0,0 +1,74 @@ +h2.heading { + border-bottom: 1px solid var(--ui-text-muted); + padding-bottom: 1rem; +} + +/* headings with no numbers */ + +article:not([autonumbering]) .heading { + position: relative; + margin-right: 2.5rem; + &__anchor-link { + display: inline-flex; + align-content: center; + margin-left: 0.25em; + position: absolute; + right: -2.5rem; + top: 3px; + font-size: 1rem; + } +} + +/* headings with autonumbering support */ + +body {counter-reset: h2} +h2 {counter-reset: h3} +h3 {counter-reset: h4} +h4 {counter-reset: h5} + +article[autonumbering] { + h2:before { + counter-increment: h2; + content: counter(h2) " "; + } + h3:before { + counter-increment: h3; + content: counter(h2) "." counter(h3) " "; + } + h4:before { + counter-increment: h4; + content: counter(h2) "." counter(h3) "." counter(h4) " "; + } + h2:before, + h3:before, + h4:before + { + margin-right: 1em; + font-family: monospace; + font-size: 1rem; + } + + .heading { + display: grid; + grid-template-columns: 1fr auto; + grid-template-rows: auto auto; + grid-gap: 0.5rem; + &__text { + grid-column: span 2; + } + &__anchor-link { + font-size: 1rem; + grid-column: 2; + grid-row: 1; + justify-self: end; + } + } + + #TableOfContents :is(ol, ul) { + counter-reset: item; + } + #TableOfContents li:before { + content: counters(item, ".") ". "; + counter-increment: item; + } +} \ No newline at end of file diff --git a/assets/styles/features/search.scss b/assets/styles/features/search.scss new file mode 100644 index 0000000..f4fd449 --- /dev/null +++ b/assets/styles/features/search.scss @@ -0,0 +1,48 @@ +.search-results__title { + display: block; + font-size: 2em; + line-height: 1; + margin-bottom: 1em; +} + +.search-results strong { + font-weight: 900; +} + +#search-results { + display: flex; + flex-flow: column; +} + +#search-results li:not(:first-child) { + border-top: 1px solid var(--ui-text-muted); +} + +#search-results li { + padding: 1em 0; +} + +#search-form { + display: flex; + justify-content: center; + align-items: center; + max-width: 100%; +} + +#search-input { + background: var(--ui-overlay); + color: var(--ui-overlay-text); + border-radius: 100rem; + border: 0; + padding: 0.5rem 1rem; + margin-right: 0.5rem; + flex-shrink: 1; +} + +#search-submit { + padding: 0.5rem 1rem; + border: 0; + background: var(--primary-accent); + color: var(--primary-accent-text); + border-radius: 4px; +} \ No newline at end of file diff --git a/assets/styles/features/syntax-highlighting.scss b/assets/styles/features/syntax-highlighting.scss new file mode 100644 index 0000000..b544de6 --- /dev/null +++ b/assets/styles/features/syntax-highlighting.scss @@ -0,0 +1,110 @@ +/* syntax highlighting */ + +.highlight { + + --error: #cc0000; + --keyword: #3361a7; + --class: #f57900; + --variable: #c049dd; + --number: #53ca24; + --operator: #5400c2; + --highlight: rgb(196, 196, 196); + + @media (prefers-color-scheme: dark) { + + --error: #cc0000; + --keyword: #e0d56e; + --class: #8700f5; + --variable: #008eb9; + --number: #53ca24; + --operator: #fffd6f; + --highlight: #555; + } + +} + +/* Background */ .bg { background-color: #f8f8f8; } +/* PreWrapper */ .chroma { background-color: #f8f8f8; } +/* Other */ .chroma .x { color: var(--ui-text-bold) } +/* Error */ .chroma .err { color: var(--error) } +/* CodeLine */ .chroma .cl { color: var(--ui-text) } +/* LineTableTD */ .chroma .lntd { vertical-align: top; padding: 0; margin: 0; border: 0; } +/* LineTable */ .chroma .lntable { border-spacing: 0; padding: 0; margin: 0; border: 0; } +/* LineHighlight */ .chroma .hl { background-color: var(--highlight) } +/* LineNumbersTable */ .chroma .lnt { white-space: pre; user-select: none; margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #7f7f7f } +/* LineNumbers */ .chroma .ln { white-space: pre; user-select: none; margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #7f7f7f } +/* Line */ .chroma .line { display: flex; white-space: pre } +/* Keyword */ .chroma .k { color: var(--keyword); font-weight: bold } +/* KeywordConstant */ .chroma .kc { color: var(--keyword); font-weight: bold } +/* KeywordDeclaration */ .chroma .kd { color: var(--keyword); font-weight: bold } +/* KeywordNamespace */ .chroma .kn { color: var(--keyword); font-weight: bold } +/* KeywordPseudo */ .chroma .kp { color: var(--keyword); font-weight: bold } +/* KeywordReserved */ .chroma .kr { color: var(--keyword); font-weight: bold } +/* KeywordType */ .chroma .kt { color: var(--keyword); font-weight: bold } +/* Name */ .chroma .n { color: var(--ui-text-bold) } +/* NameAttribute */ .chroma .na { color: var(--ui-text-bold) } +/* NameBuiltin */ .chroma .nb { color: var(--name) } +/* NameBuiltinPseudo */ .chroma .bp { color: #3465a4 } +/* NameClass */ .chroma .nc { color: var(--ui-text-bold) } +/* NameConstant */ .chroma .no { color: var(--ui-text-bold) } +/* NameDecorator */ .chroma .nd { color: var(--class); font-weight: bold } +/* NameEntity */ .chroma .ni { color: var(--name) } +/* NameException */ .chroma .ne { color: var(--error); font-weight: bold } +/* NameFunction */ .chroma .nf { color: var(--ui-text-bold) } +/* NameFunctionMagic */ .chroma .fm { color: var(--ui-text-bold) } +/* NameLabel */ .chroma .nl { color: var(--name) } +/* NameNamespace */ .chroma .nn { color: var(--ui-text-bold) } +/* NameOther */ .chroma .nx { color: var(--ui-text-bold)} +/* NameProperty */ .chroma .py { color: var(--ui-text-bold) } +/* NameTag */ .chroma .nt { color: var(--keyword); font-weight: bold } +/* NameVariable */ .chroma .nv { color: var(--variable) } +/* NameVariableClass */ .chroma .vc { color: var(--ui-text-bold)} +/* NameVariableGlobal */ .chroma .vg { color: var(--ui-text-bold) } +/* NameVariableInstance */ .chroma .vi { color: var(--ui-text-bold) } +/* NameVariableMagic */ .chroma .vm { color: var(--ui-text-bold) } +/* Literal */ .chroma .l { color: var(--ui-text-bold) } +/* LiteralDate */ .chroma .ld { color: var(--ui-text-bold) } +/* LiteralString */ .chroma .s { color: var(--variable) } +/* LiteralStringAffix */ .chroma .sa { color: var(--variable) } +/* LiteralStringBacktick */ .chroma .sb { color: var(--variable) } +/* LiteralStringChar */ .chroma .sc { color: var(--variable) } +/* LiteralStringDelimiter */ .chroma .dl { color: var(--variable) } +/* LiteralStringDoc */ .chroma .sd { color: var(--keyword); font-style: italic } +/* LiteralStringDouble */ .chroma .s2 { color: var(--variable) } +/* LiteralStringEscape */ .chroma .se { color: var(--variable) } +/* LiteralStringHeredoc */ .chroma .sh { color: var(--variable) } +/* LiteralStringInterpol */ .chroma .si { color: var(--variable) } +/* LiteralStringOther */ .chroma .sx { color: var(--variable) } +/* LiteralStringRegex */ .chroma .sr { color: var(--variable) } +/* LiteralStringSingle */ .chroma .s1 { color: var(--variable) } +/* LiteralStringSymbol */ .chroma .ss { color: var(--variable) } +/* LiteralNumber */ .chroma .m { color: var(--number); font-weight: bold } +/* LiteralNumberBin */ .chroma .mb { color: var(--number); font-weight: bold } +/* LiteralNumberFloat */ .chroma .mf { color: var(--number); font-weight: bold } +/* LiteralNumberHex */ .chroma .mh { color: var(--number); font-weight: bold } +/* LiteralNumberInteger */ .chroma .mi { color: var(--number); font-weight: bold } +/* LiteralNumberIntegerLong */ .chroma .il { color: var(--number); font-weight: bold } +/* LiteralNumberOct */ .chroma .mo { color: var(--number); font-weight: bold } +/* Operator */ .chroma .o { color: var(--operator); font-weight: bold } +/* OperatorWord */ .chroma .ow { color: var(--keyword); font-weight: bold } +/* Punctuation */ .chroma .p { color: var(--ui-text-bold); font-weight: bold } +/* Comment */ .chroma .c { color: var(--ui-text-muted); font-style: italic } +/* CommentHashbang */ .chroma .ch { color: var(--ui-text-muted); font-style: italic } +/* CommentMultiline */ .chroma .cm { color: var(--ui-text-muted); font-style: italic } +/* CommentSingle */ .chroma .c1 { color: var(--ui-text-muted); font-style: italic } +/* CommentSpecial */ .chroma .cs { color: var(--ui-text-muted); font-style: italic } +/* CommentPreproc */ .chroma .cp { color: var(--ui-text-muted); font-style: italic } +/* CommentPreprocFile */ .chroma .cpf { color: var(--ui-text-muted); font-style: italic } +/* Generic */ .chroma .g { color: var(--ui-text-bold) } +/* GenericDeleted */ .chroma .gd { color: var(--error) } +/* GenericEmph */ .chroma .ge { color: var(--ui-text-bold); font-style: italic } +/* GenericError */ .chroma .gr { color: var(--error) } +/* GenericHeading */ .chroma .gh { color: var(--ui-text-bold); font-weight: bold } +/* GenericInserted */ .chroma .gi { color: var(--ui-text) } +/* GenericOutput */ .chroma .go { color: var(--ui-text-bold); font-style: italic } +/* GenericPrompt */ .chroma .gp { color: var(--ui-text) } +/* GenericStrong */ .chroma .gs { color: var(--ui-text-bold); font-weight: bold } +/* GenericSubheading */ .chroma .gu { color: var(--ui-text-bold); font-weight: bold } +/* GenericTraceback */ .chroma .gt { color: var(--error); font-weight: bold } +/* GenericUnderline */ .chroma .gl { color: var(--ui-text-bold); text-decoration: underline } +/* TextWhitespace */ .chroma .w { color: var(--ui-text-muted); text-decoration: underline } \ No newline at end of file diff --git a/assets/styles/print.scss b/assets/styles/print.scss index 92663d4..774c7b7 100644 --- a/assets/styles/print.scss +++ b/assets/styles/print.scss @@ -1,15 +1,22 @@ @import "common/reset"; @import "common/colors"; @import "common/base"; -@import "common/page"; +@import "common/content"; @import "components/site-header"; +@import "components/single/page-header"; +@import "components/breadcrumbs"; +@import "components/table-of-contents"; +@import "features/headings"; +#search-form, .header-nav, .docs-nav, .site-footer, .edit-link, -.footnote-backref +.footnote-backref, +.heading__anchor-link, +.section-nav { display: none; } diff --git a/assets/styles/screen.scss b/assets/styles/screen.scss index 0ef4dc2..6acd462 100644 --- a/assets/styles/screen.scss +++ b/assets/styles/screen.scss @@ -1,12 +1,21 @@ @import "common/reset"; @import "common/colors"; @import "common/base"; -@import "common/page"; +@import "common/content"; @import "components/site-header"; -@import "components/header-menu"; -@import "components/docs-menu"; +@import "components/nav-header"; +@import "components/nav-docs"; @import "components/site-footer"; +@import "components/single/page-header"; +@import "components/breadcrumbs"; +@import "components/table-of-contents"; +@import "components/nav-section"; + +@import "features/headings"; +@import "features/syntax-highlighting"; +@import "features/search"; + @import "screen/layout"; @import "screen/links"; diff --git a/assets/styles/screen/layout.scss b/assets/styles/screen/layout.scss index 31996c4..bbf0920 100644 --- a/assets/styles/screen/layout.scss +++ b/assets/styles/screen/layout.scss @@ -1,18 +1,3 @@ -/* single layout */ - -.page { - .page-title {margin-top: 0;} - .lastmod { - margin-top: 1em; - color: var(--ui-text-muted) - } - .language-list { - display: flex; - flex-flow: wrap; - list-style: none; - } -} - /* [responsive] re-show the navigation menu as a sidebar */ @media (min-width: 60rem) { @@ -24,6 +9,11 @@ .site-header, .scroll-margin, .site-footer { grid-column: span 2 } + + .site-footer { /* fixed height footer */ + height: var(--footer-height); + } + .docs-nav { grid-column: 1; height: calc(100 * var(--vh, 1vh) - var(--header-height) - var(--footer-height)); @@ -102,7 +92,8 @@ /* start limiting content since it can exceed 80ch now */ - .page .content .container { + .content .container + { display: grid; grid-template-columns: minmax(0, 1fr) minmax(auto, 80ch) minmax(0, 1fr); > * { @@ -114,9 +105,20 @@ } } + .section-nav, + .page-footer .container + { + display: grid; + grid-template-columns: minmax(0, 1fr) minmax(auto, 80ch) minmax(0, 1fr); + > .container { + padding: 0; + grid-column: 2; + } + } + /* also make the page header line up */ - .page .page-header { + .page-header { display: grid; grid-template-columns: minmax(0, 1fr) minmax(auto, 80ch) minmax(0, 1fr); > .container { diff --git a/assets/styles/screen/links.scss b/assets/styles/screen/links.scss index b74dee5..525e385 100644 --- a/assets/styles/screen/links.scss +++ b/assets/styles/screen/links.scss @@ -26,4 +26,21 @@ a:hover { @media (prefers-reduced-motion) { a:link {transition: none} -} \ No newline at end of file +} + +/* mark external links */ + +a[href^="http"]:after { + content: "🡕"; +} + +a[href^="{{.Site.BaseURL}}"]:after +{ + display: none !important; +} + +a[href^="http://localhost"]:after +{ + display: none !important; +} + diff --git a/layouts/_default/_markup/render-heading.html b/layouts/_default/_markup/render-heading.html new file mode 100644 index 0000000..1076ca4 --- /dev/null +++ b/layouts/_default/_markup/render-heading.html @@ -0,0 +1,6 @@ + + {{.Text | safeHTML}} + + [link] + + \ No newline at end of file diff --git a/layouts/_default/baseof.html b/layouts/_default/baseof.html index 2096438..74ef541 100644 --- a/layouts/_default/baseof.html +++ b/layouts/_default/baseof.html @@ -1,29 +1,30 @@ - - - - - - {{ $screen := resources.Get "styles/screen.scss" | toCSS | minify | fingerprint }} - - {{ $print := resources.Get "styles/print.scss" | toCSS | minify | fingerprint }} - - {{ $script := resources.Get "scripts/main.js" | js.Build "script.js" | minify | fingerprint }} - - {{ partial "seo.html" . }} - {{ block "head" . }} - {{ end }} - + + + + + +{{ $screen := resources.Get "styles/screen.scss" | toCSS | minify | fingerprint }} + +{{ $print := resources.Get "styles/print.scss" | toCSS | minify | fingerprint }} + +{{ $script := resources.Get "scripts/main.js" | js.Build "script.js" | minify | fingerprint }} + + +{{ partial "seo.html" . }} +{{ block "head" . }} +{{ end }} + {{ partial "site-header.html" . }} {{ block "main" . }} diff --git a/layouts/_default/single.html b/layouts/_default/single.html index 7386b9c..2783e36 100644 --- a/layouts/_default/single.html +++ b/layouts/_default/single.html @@ -1,12 +1,14 @@ {{ define "main" }}
    -
    +
    @@ -21,6 +23,12 @@ {{ .Content }} + {{ partial "nav-section.html" . }} +
    +
    + {{ partial "page-footer.html" . }} +
    +
    {{ end }} diff --git a/layouts/index.html b/layouts/index.html index dd1ccc3..54335ed 100644 --- a/layouts/index.html +++ b/layouts/index.html @@ -17,7 +17,7 @@
    {{ .Content }} -

    Last modified {{ .Lastmod.Format "Mon Jan 2, 2006" }} - Edit this page

    +

    Last modified {{ .Lastmod.Format "Mon Jan 2, 2006" }}
    Edit this page

    diff --git a/layouts/index.json b/layouts/index.json new file mode 100644 index 0000000..d423a62 --- /dev/null +++ b/layouts/index.json @@ -0,0 +1,8 @@ +{{- $.Scratch.Add "pagesIndex" slice -}} +{{- range $index, $page := .Site.RegularPages -}} + {{- if gt (len $page.Content) 0 -}} + {{- $pageData := (dict "title" $page.Title "href" $page.Permalink "content" $page.Plain) -}} + {{- $.Scratch.Add "pagesIndex" $pageData -}} + {{- end -}} +{{- end -}} +{{- $.Scratch.Get "pagesIndex" | jsonify -}} \ No newline at end of file diff --git a/layouts/partials/nav-docs.html b/layouts/partials/nav-docs.html index 13a03f4..c3b0656 100644 --- a/layouts/partials/nav-docs.html +++ b/layouts/partials/nav-docs.html @@ -12,7 +12,7 @@ {{ if .HasChildren}}
  • - + {{ .Pre }} {{ .Name }} {{ .Post }} @@ -22,7 +22,7 @@ {{ if .HasChildren}}
  • - + {{ .Pre }} {{ .Name }} {{ .Post }} @@ -31,7 +31,7 @@ {{ range .Children }}
  • - + {{ .Pre }} {{ .Name }} {{ .Post }} @@ -43,7 +43,7 @@ {{ else }}
  • - + {{ .Pre }} {{ .Name }} {{ .Post }} @@ -56,7 +56,7 @@ {{ else }}
  • - + {{ .Pre }} {{ .Name }} {{ .Post }} diff --git a/layouts/partials/nav-footer.html b/layouts/partials/nav-footer.html index 45365d0..b5cb518 100644 --- a/layouts/partials/nav-footer.html +++ b/layouts/partials/nav-footer.html @@ -4,7 +4,7 @@ {{ range .Site.Menus.footer }}
  • - + {{ .Pre }} {{ .Name }} {{ .Post }} diff --git a/layouts/partials/nav-header.html b/layouts/partials/nav-header.html index e30cd36..d8e8348 100644 --- a/layouts/partials/nav-header.html +++ b/layouts/partials/nav-header.html @@ -1,19 +1,15 @@ \ No newline at end of file diff --git a/layouts/partials/nav-section.html b/layouts/partials/nav-section.html new file mode 100644 index 0000000..e91f0f6 --- /dev/null +++ b/layouts/partials/nav-section.html @@ -0,0 +1,10 @@ + \ No newline at end of file diff --git a/layouts/partials/page-footer.html b/layouts/partials/page-footer.html new file mode 100644 index 0000000..69e031c --- /dev/null +++ b/layouts/partials/page-footer.html @@ -0,0 +1,4 @@ +{{/* + Override this partial if you want stuff + to show up at the bottom of each page +*/}} \ No newline at end of file diff --git a/layouts/partials/search/search-form.html b/layouts/partials/search/search-form.html new file mode 100644 index 0000000..47c788e --- /dev/null +++ b/layouts/partials/search/search-form.html @@ -0,0 +1,5 @@ +
    + + + +
    diff --git a/layouts/partials/search/search-index.html b/layouts/partials/search/search-index.html new file mode 100644 index 0000000..c86a7b0 --- /dev/null +++ b/layouts/partials/search/search-index.html @@ -0,0 +1,3 @@ + +{{ $js := resources.Get "scripts/search.js" | minify | fingerprint }} + \ No newline at end of file diff --git a/layouts/partials/seo.html b/layouts/partials/seo.html index 0bdf2eb..669211e 100644 --- a/layouts/partials/seo.html +++ b/layouts/partials/seo.html @@ -1,10 +1,6 @@ {{ $icon := "images/icon.png" | absURL }} -{{ if .IsPage }} - {{ with .Params.tags }} - - {{ end }} -{{ end }} +{{ if .IsPage }}{{ with .Params.tags }}{{ end }}{{ end }} {{ if .IsHome }}{{ .Site.Title }} {{ .Site.Title }} diff --git a/layouts/partials/site-footer.html b/layouts/partials/site-footer.html index 725da41..8b6d0b1 100644 --- a/layouts/partials/site-footer.html +++ b/layouts/partials/site-footer.html @@ -5,4 +5,5 @@ back to top +{{ partial "search/search-index.html" . }} diff --git a/layouts/partials/site-header.html b/layouts/partials/site-header.html index 614cf84..c68dae3 100644 --- a/layouts/partials/site-header.html +++ b/layouts/partials/site-header.html @@ -4,6 +4,7 @@

    {{.Site.Params.title}}

    + {{ partial "search/search-form.html" . }} {{ partial "nav-header.html" . }} diff --git a/layouts/search/list.html b/layouts/search/list.html new file mode 100644 index 0000000..8319ad3 --- /dev/null +++ b/layouts/search/list.html @@ -0,0 +1,21 @@ +{{ define "main" }} +
    +
    +
    +
    +

    for ""

    +
    +
    +
    +
    +
      + +
    +
    +
    +
    +
    + +{{ end }} \ No newline at end of file