summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSerghei Iakovlev <egrep@protonmail.ch>2022-07-24 13:05:46 +0200
committerSerghei Iakovlev <egrep@protonmail.ch>2022-07-24 13:05:46 +0200
commit6d842eefd0831c89f3be60e85dba91304fd3d00d (patch)
tree04a246f5657986e560b2402073a5e8ecf2c82b7e
parent6be75b5d6ac6ea9e26569bb553a67218e75d2ae2 (diff)
downloadgohugo-theme-ed-6d842eefd0831c89f3be60e85dba91304fd3d00d.tar.gz
Provide 'Back to top' functionality
-rw-r--r--CHANGELOG.md1
-rw-r--r--assets/js/ed.js14
-rw-r--r--assets/sass/_customize.scss62
-rw-r--r--assets/sass/_ed.scss2
-rw-r--r--assets/sass/_form-elements.scss6
-rw-r--r--assets/sass/_mixins.scss53
-rw-r--r--exampleSite/config/_default/config.yaml2
-rw-r--r--i18n/en.toml6
-rw-r--r--i18n/ru.toml6
-rw-r--r--layouts/_default/baseof.html12
-rw-r--r--layouts/partials/head.html3
-rw-r--r--layouts/partials/scripts.html14
-rw-r--r--resources/_gen/assets/scss/sass/style.scss_f300667da4f5b5f84e1a9e0702b2fdde.content50
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 {