diff options
| author | Serghei Iakovlev <egrep@protonmail.ch> | 2022-07-24 13:05:46 +0200 |
|---|---|---|
| committer | Serghei Iakovlev <egrep@protonmail.ch> | 2022-07-24 13:05:46 +0200 |
| commit | 6d842eefd0831c89f3be60e85dba91304fd3d00d (patch) | |
| tree | 04a246f5657986e560b2402073a5e8ecf2c82b7e | |
| parent | 6be75b5d6ac6ea9e26569bb553a67218e75d2ae2 (diff) | |
| download | gohugo-theme-ed-6d842eefd0831c89f3be60e85dba91304fd3d00d.tar.gz | |
Provide 'Back to top' functionality
| -rw-r--r-- | CHANGELOG.md | 1 | ||||
| -rw-r--r-- | assets/js/ed.js | 14 | ||||
| -rw-r--r-- | assets/sass/_customize.scss | 62 | ||||
| -rw-r--r-- | assets/sass/_ed.scss | 2 | ||||
| -rw-r--r-- | assets/sass/_form-elements.scss | 6 | ||||
| -rw-r--r-- | assets/sass/_mixins.scss | 53 | ||||
| -rw-r--r-- | exampleSite/config/_default/config.yaml | 2 | ||||
| -rw-r--r-- | i18n/en.toml | 6 | ||||
| -rw-r--r-- | i18n/ru.toml | 6 | ||||
| -rw-r--r-- | layouts/_default/baseof.html | 12 | ||||
| -rw-r--r-- | layouts/partials/head.html | 3 | ||||
| -rw-r--r-- | layouts/partials/scripts.html | 14 | ||||
| -rw-r--r-- | resources/_gen/assets/scss/sass/style.scss_f300667da4f5b5f84e1a9e0702b2fdde.content | 50 |
13 files changed, 208 insertions, 23 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index d087505..e4bc6f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 (will be used for Schema.org) - Provide ability to mark links as external using svg icon - Provide minimal tag cloud +- Provide 'Back to top' functionality ### Changed diff --git a/assets/js/ed.js b/assets/js/ed.js new file mode 100644 index 0000000..dbea865 --- /dev/null +++ b/assets/js/ed.js @@ -0,0 +1,14 @@ +document.addEventListener('DOMContentLoaded', function () { + // 'Back to top' logic + const intersectionObserver = new IntersectionObserver(function(entries) { + const topBtn = document.querySelector('.top-of-site-link'); + if (topBtn === null) return; + + topBtn.dataset.visible = entries[0].boundingClientRect.y < 0; + }); + + const topAnchor = document.querySelector('#top-of-site-anchor'); + if (topAnchor !== null) { + intersectionObserver.observe(topAnchor); + } +}); diff --git a/assets/sass/_customize.scss b/assets/sass/_customize.scss index 085bb6f..82cfcf4 100644 --- a/assets/sass/_customize.scss +++ b/assets/sass/_customize.scss @@ -163,7 +163,7 @@ ul.pager { color: #fff; text-decoration: none; - @include border-radius (0 4px 4px 0); + @include border-radius(0 4px 4px 0); &:before { content: ""; @@ -188,8 +188,8 @@ ul.pager { height: 4px; background: #fff; - @include border-radius (2px); - @include box-shadow (-1px -1px 2px $text-color); + @include border-radius(2px); + @include box-shadow(-1px -1px 2px $text-color); } &:hover { @@ -211,8 +211,8 @@ a.external { margin-left: 4px; width: 10px; - @include mask-size (cover); - @include mask-image (url("/img/external-link.svg")); + @include mask-size(cover); + @include mask-image(url("/img/external-link.svg")); } } @@ -238,3 +238,55 @@ ul.tags-cloud { @include transition(0.3s); } } + +#top-of-site-anchor { + position: absolute; + width: 1px; + height: 1px; + top: 500px; + left: 0; +} + +@media (max-width: 800px){ + #top-of-site-anchor { + top: 46px; + } +} + +.top-of-site-link { + visibility: hidden; + opacity: 0; + text-decoration: none; + position: fixed; + bottom: 1.2rem; + right: 1.5rem; + z-index: 99; + + @include transition(.2s); + + &:hover { + text-decoration: none; + } + + svg { + @include filter(drop-shadow(0 2px 5px rgba(0, 0, 0, .3))); + } +} + +.top-of-site-link[data-visible=true] { + opacity: 1; + visibility: visible; +} + +.screen-reader-text { + position: absolute; + word-wrap: normal; + border: 0; + height: 1px; + width: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + + @include clip-path(inset(50%)); +} diff --git a/assets/sass/_ed.scss b/assets/sass/_ed.scss index 2f26ad1..b0870dc 100644 --- a/assets/sass/_ed.scss +++ b/assets/sass/_ed.scss @@ -25,7 +25,7 @@ */ * { - @include box-sizing (border-box); + @include box-sizing(border-box); } html, diff --git a/assets/sass/_form-elements.scss b/assets/sass/_form-elements.scss index 5948213..cbb6c08 100644 --- a/assets/sass/_form-elements.scss +++ b/assets/sass/_form-elements.scss @@ -24,7 +24,7 @@ } &:focus { - @include box-shadow (none); + @include box-shadow(none); outline: none; border-color: #5e5e5e; } @@ -73,13 +73,13 @@ form textarea:-moz-submit-invalid, form input[type="text"]:-moz-submit-invalid, form select:-moz-submit-invalid, form input:-moz-ui-invalid { - @include box-shadow (0 0 2px 1px #D64541!important); + @include box-shadow(0 0 2px 1px #D64541!important); } .form-item-error { .form-input, .form-textarea { - @include box-shadow (0 0 2px 1px #D64541!important); + @include box-shadow(0 0 2px 1px #D64541!important); } } diff --git a/assets/sass/_mixins.scss b/assets/sass/_mixins.scss index ae030d4..95e63e4 100644 --- a/assets/sass/_mixins.scss +++ b/assets/sass/_mixins.scss @@ -122,7 +122,7 @@ $break-desktop: 1600px; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Box Sizing // Sets how the total width and height of an element is calculated. // -// Usage: @include box-sizing (border-box); +// Usage: @include box-sizing(border-box); @mixin box-sizing ($value) { -webkit-box-sizing: $value; @@ -133,7 +133,7 @@ $break-desktop: 1600px; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Box Shadow // -// Usage: @include box-shadow (0 0 2px 1px #e21a23!important); +// Usage: @include box-shadow(0 0 2px 1px #e21a23!important); @mixin box-shadow ($args...) { -webkit-box-shadow: $args; @@ -143,7 +143,7 @@ $break-desktop: 1600px; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Border Radius // -// Usage: @include border-radius (10% 30% 50% 70%); +// Usage: @include border-radius(10% 30% 50% 70%); @mixin border-radius ($args...) { -webkit-border-radius: $args; @@ -155,7 +155,7 @@ $break-desktop: 1600px; // Sets whether flex items are forced onto one line or can wrap onto // multiple lines. // -// Usage: @include flex-wrap (wrap); +// Usage: @include flex-wrap(wrap); @mixin flex-wrap ($value) { -webkit-flex-wrap: $value; @@ -167,7 +167,7 @@ $break-desktop: 1600px; // Specifies how an element's fragments should be rendered when broken across // multiple lines, columns, or pages. // -// Usage: @include box-decoration-break (clone); +// Usage: @include box-decoration-break(clone); @mixin box-decoration-break ($value) { -webkit-box-decoration-break: $value; @@ -178,16 +178,47 @@ $break-desktop: 1600px; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Mask -// Usage: @include @include mask-image (url("/img/external-link.svg")); +// Usage: @include mask-image(url("/img/external-link.svg")); @mixin mask-image($value) { - -webkit-mask-image: $value; // Chrome, iOS, Safari - mask-image: $value; // None yet / Non-standard + -webkit-mask-image: $value; + mask-image: $value; } -// Usage: @include mask-size (cover); +// Usage: @include mask-size(cover); @mixin mask-size($value) { - -webkit-mask-size: $value; // Chrome, iOS, Safari - mask-size: $value; // None yet / Non-standard + -webkit-mask-size: $value; + mask-size: $value; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Filter +// Applies graphical effects like blur or color shift to an element. +// +// Usage: @include filter(drop-shadow(0 2px 5px rgba(0, 0, 0, .3))); + +@mixin filter($value) { + -webkit-filter: $value; + -moz-filter: $value; // editorconfig-checker-disable-line + -o-filter: $value; // editorconfig-checker-disable-line + filter: $value; +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - clip-path +// Create a clipping region that sets what part of an element should be shown. +// +// Usage: @include clip-path( +// padding-box, +// circle(50px at 0 100px), +// // ... +// ); + +@mixin clip-path($clip-list...) { + // combine the passed transforms into a space separated list + $clip-list: join($clip-list, null, space); + + -webkit-clip-path: $clip-list; + -moz-clip-path: $clip-list; + -ms-clip-path: $clip-list; + clip-path: $clip-list; } diff --git a/exampleSite/config/_default/config.yaml b/exampleSite/config/_default/config.yaml index 9a6320c..930f608 100644 --- a/exampleSite/config/_default/config.yaml +++ b/exampleSite/config/_default/config.yaml @@ -38,7 +38,7 @@ taxonomies: # # Set `HUGO_ENV` environment variable or `site.Params.env` configuration # parameter to "production" to use Google Analytics. -googleAnalytics: 'xxx' +googleAnalytics: '' minify: # Do not minify XML files to avoid CDATA escape issues diff --git a/i18n/en.toml b/i18n/en.toml index 0c786b7..bbdff71 100644 --- a/i18n/en.toml +++ b/i18n/en.toml @@ -66,3 +66,9 @@ [tag_cloud] other = 'Tag Cloud' + +[back_to_top] + other = 'Back to top' + +[back_to_top_label] + other = 'Back to top of the page' diff --git a/i18n/ru.toml b/i18n/ru.toml index 40aba8c..abddef4 100644 --- a/i18n/ru.toml +++ b/i18n/ru.toml @@ -66,3 +66,9 @@ [tag_cloud] other = 'Облако тегов' + +[back_to_top] + other = 'Вернуться в начало' + +[back_to_top_label] + other = 'Вернуться в начало страницы' diff --git a/layouts/_default/baseof.html b/layouts/_default/baseof.html index 4985ca3..5f095c2 100644 --- a/layouts/_default/baseof.html +++ b/layouts/_default/baseof.html @@ -1,7 +1,8 @@ <!DOCTYPE html> -<html lang="{{ site.LanguageCode | default site.Language.Lang }}" {{- with partialCached "func/GetLanguageDirection" "GetLanguageDirection" }} dir="{{ . }}" {{- end }} prefix="og: http://ogp.me/ns#"> +<html lang="{{ site.LanguageCode | default site.Language.Lang }}" {{- with partialCached "func/GetLanguageDirection" "GetLanguageDirection" }} dir="{{ . }}" {{- end }} prefix="og: http://ogp.me/ns#" id="top-of-site"> {{ partial "head.html" . }} <body class="theme-base-{{ site.Params.colorScheme }}"> + <div id="top-of-site-anchor"></div> {{ if .Params.toc }} {{ partial "sidebar-toc.html" . }} {{ else }} @@ -23,5 +24,14 @@ </div> <label for="sidebar-checkbox" class="sidebar-toggle"></label> + + <a href="#top-of-site" class="top-of-site-link" data-visible="false"> + <span class="screen-reader-text" aria-label="{{ i18n "back_to_top_label" }}"> + {{ i18n "back_to_top" }} + </span> + <svg width="32" height="32" viewBox="0 0 100 100"> + <path fill="white" d="m50 0c-13.262 0-25.98 5.2695-35.355 14.645s-14.645 22.094-14.645 35.355 5.2695 25.98 14.645 35.355 22.094 14.645 35.355 14.645 25.98-5.2695 35.355-14.645 14.645-22.094 14.645-35.355-5.2695-25.98-14.645-35.355-22.094-14.645-35.355-14.645zm20.832 62.5-20.832-22.457-20.625 22.457c-1.207 0.74219-2.7656 0.57812-3.7891-0.39844-1.0273-0.98047-1.2695-2.5273-0.58594-3.7695l22.918-25c0.60156-0.61328 1.4297-0.96094 2.2891-0.96094 0.86328 0 1.6914 0.34766 2.293 0.96094l22.918 25c0.88672 1.2891 0.6875 3.0352-0.47266 4.0898-1.1562 1.0508-2.9141 1.0859-4.1133 0.078125z"></path> + </svg> + </a> </body> </html> diff --git a/layouts/partials/head.html b/layouts/partials/head.html index 934ccc9..036b26d 100644 --- a/layouts/partials/head.html +++ b/layouts/partials/head.html @@ -35,6 +35,7 @@ {{- template "partials/templates/twitter_cards.html" . }} {{- template "partials/templates/schema_json.html" . }} - {{- /* SEO */}} + {{- /* Scripts */}} + {{- partial "partials/scripts.html" . }} {{- partial "partials/seo/ga.html" . }} </head> diff --git a/layouts/partials/scripts.html b/layouts/partials/scripts.html new file mode 100644 index 0000000..a42e492 --- /dev/null +++ b/layouts/partials/scripts.html @@ -0,0 +1,14 @@ +{{- $isProduction := (or (eq (getenv "HUGO_ENV") "production") (eq site.Params.env "production")) -}} + +{{- $scripts := slice -}} +{{- $scripts = $scripts | append (resources.Get "js/ed.js") -}} +{{- $scripts = $scripts | resources.Concat "js/common.js" -}} + +{{- $scripts = $scripts | js.Build (dict "format" "iife" "minify" $isProduction) -}} + +{{- if or (site.Params.assets.disable_fingerprinting) (not $isProduction) }} + <script src="{{ $scripts.RelPermalink }}"></script> +{{- else -}} + {{- $scripts = $scripts | fingerprint }} + <script src="{{ $scripts.RelPermalink }}" integrity="{{ $scripts.Data.Integrity }}"></script> +{{- end -}} diff --git a/resources/_gen/assets/scss/sass/style.scss_f300667da4f5b5f84e1a9e0702b2fdde.content b/resources/_gen/assets/scss/sass/style.scss_f300667da4f5b5f84e1a9e0702b2fdde.content index 69adea0..afc21d5 100644 --- a/resources/_gen/assets/scss/sass/style.scss_f300667da4f5b5f84e1a9e0702b2fdde.content +++ b/resources/_gen/assets/scss/sass/style.scss_f300667da4f5b5f84e1a9e0702b2fdde.content @@ -1075,6 +1075,56 @@ ul.tags-cloud { -o-transition: 0.3s; transition: 0.3s; } +#top-of-site-anchor { + position: absolute; + width: 1px; + height: 1px; + top: 500px; + left: 0; } + +@media (max-width: 800px) { + #top-of-site-anchor { + top: 46px; } } + +.top-of-site-link { + visibility: hidden; + opacity: 0; + text-decoration: none; + position: fixed; + bottom: 1.2rem; + right: 1.5rem; + z-index: 99; + -webkit-transition: 0.2s; + -moz-transition: 0.2s; + -ms-transition: 0.2s; + -o-transition: 0.2s; + transition: 0.2s; } + .top-of-site-link:hover { + text-decoration: none; } + .top-of-site-link svg { + -webkit-filter: drop-shadow(0 2px 5px rgba(0, 0, 0, 0.3)); + -moz-filter: drop-shadow(0 2px 5px rgba(0, 0, 0, 0.3)); + -o-filter: drop-shadow(0 2px 5px rgba(0, 0, 0, 0.3)); + filter: drop-shadow(0 2px 5px rgba(0, 0, 0, 0.3)); } + +.top-of-site-link[data-visible=true] { + opacity: 1; + visibility: visible; } + +.screen-reader-text { + position: absolute; + word-wrap: normal; + border: 0; + height: 1px; + width: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + -webkit-clip-path: inset(50%); + -moz-clip-path: inset(50%); + -ms-clip-path: inset(50%); + clip-path: inset(50%); } + /* Themes */ /* Red */ .theme-base-red .post-tags a { |
