Compare commits

...
40 Commits
Author SHA1 Message Date
Jimmy CaiandGitHub 8f5164b5b9 chore: add go.mod again 2022-03-05 17:35:18 +00:00
Jimmy CaiandGitHub 07da61b1f2 chore: delete go.mod 2022-03-05 17:25:02 +00:00
Jimmy CaiandGitHub 76925213a3 chore: update go.mod
Trying to figure out what's wrong
2022-03-05 17:22:11 +00:00
Jimmy CaiandGitHub 0317e19ef2 fix(RSS): page context selection 2022-03-05 17:15:08 +00:00
Jimmy CaiandGitHub 863e6d4116 Resolve merge conflict 2022-03-05 17:14:24 +00:00
Jimmy CaiandGitHub 72629cf476 Merge branch 'fix-rss-pctx' of https://github.com/nella17/hugo-theme-stack into nella17-fix-rss-pctx 2022-03-05 17:13:42 +00:00
Jimmy CaiandGitHub d455336d57 fix: remove section filter in rss.xml 2022-03-05 18:11:48 +01:00
Jimmy Cai 5449f786ac release: 3.9.0 2022-03-04 10:40:41 +01:00
Jimmy CaiandGitHub 6f60f4f552 fix: disable external image lightbox (#525) 2022-03-04 10:31:57 +01:00
Jimmy CaiandGitHub 985af924e7 feat: new left sidebar layout (#524)
* feat: more compact menu style

* add compact option to sidebar

* fix mobile menu style
2022-03-04 10:24:21 +01:00
Jimmy CaiandGitHub c122e5e9a1 chore(exampleSite): remove extra home menu item 2022-03-04 08:47:51 +00:00
Jimmy CaiandGitHub 15d2040f7e chore(exampleSite): fix home menu item highlight 2022-03-04 08:46:27 +00:00
Jimmy CaiandGitHub 79e23544a9 Merge branch 'master' of https://github.com/CaiJimmy/hugo-theme-stack 2022-03-04 08:41:50 +00:00
Jimmy CaiandGitHub c4e864a08d doc(exampleSite): move chinese-test post to /cn 2022-03-04 08:41:47 +00:00
Jimmy CaiandGitHub dbf4c2e58f chore: add Github link to funding.yml 2022-03-04 09:39:27 +01:00
FarisZRandGitHub 47c19a0fbc feat(i18n): add Arabic translation (#157) 2022-03-04 00:28:17 +01:00
FarisZRandGitHub 0d0375a7fc feat: add RTL Support and update demo site to Show Arabic/RTL content (#519)
* add LanguageDirection variable

* add .direction-rtl and .direction-ltr clases

* margin -right > margin-inline-end

* keep Codeblocks LTR

* switch to logical properties

* left -> inset-inline-start

* Add Arabic/RTL placeholder text

* Add arabic language

* remove space

* use Html Dir instead of class

* Move codeblock code to layout/article.css and fix 4 spaces codeblocks

* remove unused clases
2022-03-04 00:25:34 +01:00
Jimmy CaiandGitHub 86ad00cf8c doc: add categories widget to exampleSite 2022-03-03 22:48:26 +00:00
e22664be13 feat(widget): add category widget (#475)
* Add category widget

Adds the ability to add a category to the widgets.

* Adapt to new widget scheme

Co-authored-by: Jimmy Cai <[email protected]>
2022-03-03 23:47:10 +01:00
Jimmy CaiandGitHub d806226ec8 fix: article-details gap 2022-03-03 22:39:04 +00:00
Jimmy CaiandGitHub 8abaa444c1 refactor: add flexbox gap to .article-details 2022-03-03 22:36:17 +00:00
Jimmy CaiandGitHub 04cdbcfedf refactor: Use flexbox gap (#520) 2022-03-03 23:11:19 +01:00
Jimmy CaiandGitHub adf27aebf2 Revert "fix(RSS): hidden post visible on feed (#514)" (#517) 2022-03-03 07:31:03 +01:00
Allen Guan 9dbc0a4f38 fix(RSS): page context selection 2022-03-03 12:38:47 +08:00
zhixuanandGitHub 24cd07589b feat(comments): add lang option for giscus (#498) 2022-03-02 21:31:44 +01:00
Allen GuanandGitHub 98923b1dd7 fix(RSS): hidden post visible on feed (#514) 2022-03-02 21:24:56 +01:00
Jimmy CaiandGitHub 2712887c7c feat: multilingual site switch (#512)
* feat: multilingual site switch

* fix menu item margin

switch to flexbox gap
2022-02-27 10:51:02 +01:00
Jimmy CaiandGitHub b3b8fa73ef feat(article): add link to translated content (#511) 2022-02-27 09:48:57 +01:00
JesseJesonandGitHub 26fb06951b chore: update twikoo version to 1.4.18 (#496) 2022-02-26 23:49:26 +01:00
Jimmy CaiandGitHub 4d552a9df5 feat: article page widget support (#488)
* feat: article page widget support

* refactor: get rid of article toolbar

Same 3 column layout for article page and homepage

* add missing space
2022-02-26 23:45:25 +01:00
Jimmy CaiandGitHub 0fbbc12949 fix: check if paragraph exists before accessing it's textContent
closes https://github.com/CaiJimmy/hugo-theme-stack/issues/490
2022-02-12 13:23:38 +00:00
Jimmy CaiandGitHub 4b0dbb4630 fix(article): code block background style in light theme
closes https://github.com/CaiJimmy/hugo-theme-stack/issues/489, https://github.com/CaiJimmy/hugo-theme-stack/issues/492
2022-02-11 20:36:52 +00:00
Jimmy CaiandGitHub ce57ea915e chore: add /v3 to go.mod 2022-02-06 20:48:44 +01:00
Jimmy CaiandGitHub 9f36a956ca release: 3.8.0 2022-02-06 19:36:10 +00:00
Jimmy CaiandGitHub d75dbe2b6e fix: copy code button does not work when line number is enabled (#487)
* fix: copy code button does not work when line number is enabled

* fix pre style

* Add gist shortcode to exampleSite
2022-02-06 20:32:37 +01:00
Jimmy CaiandGitHub 88beecd101 fix: hyperlinked image (#485)
* fix: hyperlinked image

closes https://github.com/CaiJimmy/hugo-theme-stack/issues/410

* feat: add support to inline images

* Remove unused code

* Remove data-alt-html
2022-02-06 19:58:10 +01:00
Jimmy CaiandGitHub 67d5156507 fix: disqus dark mode (#478)
* fix: disqus dark mode

* remove color-scheme

add custom chrome scrollbar style (removed in https://github.com/CaiJimmy/hugo-theme-stack/pull/428)
2022-01-30 10:57:16 +01:00
Jimmy CaiandGitHub 6474b9dfd8 fix(comments): fix cactus comments
closes https://github.com/CaiJimmy/hugo-theme-stack/issues/470
2022-01-23 12:59:21 +00:00
MarcelandGitHub 7dc5def217 feat(comments): add https://cactus.chat support (#298)
* feat: Add https://cactus.chat as comments provider

* Add cactus comments config fields to exampleSite

* Add cactus css and js to external.yaml and move custom cactus css to html

* Remove unneeded cactus comments css

* Load external dependencies for cactus comments in the comments provider

* Use safeJS instead of safeHTML
2022-01-23 13:10:00 +01:00
ZoroarkandGitHub 2b40a32d47 feat(article): Scrollspy for the table of contents (#425)
* Add first try at scrollspy (broken right now)

* Scrollspy actually works now

* Fix VS Code errors by setting JS version

* Recompute offsets when window size changes

* Improve list compatibility for toc active selection

Support up to 6 levels of indentation, properly support <ol>

* Remove debug string

* Add more docs in smoothAnchors

* Use a map to match ids to navigation elements
2022-01-22 10:35:08 +01:00
57 changed files with 1025 additions and 514 deletions
+1
View File
@@ -1 +1,2 @@
ko_fi: jimmycai
github: CaiJimmy
+1
View File
@@ -1,3 +1,4 @@
public
resources
assets/jsconfig.json
.hugo_build.lock
+9
View File
@@ -0,0 +1,9 @@
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-hash" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z"/>
<line x1="5" y1="9" x2="19" y2="9" />
<line x1="5" y1="15" x2="19" y2="15" />
<line x1="11" y1="4" x2="7" y2="20" />
<line x1="17" y1="4" x2="13" y2="20" />
</svg>

After

Width:  |  Height:  |  Size: 440 B

+10
View File
@@ -0,0 +1,10 @@
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-language" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
<path d="M4 5h7" />
<path d="M9 3v2c0 4.418 -2.239 8 -5 8" />
<path d="M5 9c-.003 2.144 2.952 3.908 6.7 4" />
<path d="M12 20l4 -9l4 9" />
<path d="M19.1 18h-6.2" />
</svg>

After

Width:  |  Height:  |  Size: 467 B

+9 -20
View File
@@ -11,7 +11,7 @@
/// Display right sidebar when min-width: lg
@include respond(lg) {
display: block;
display: flex;
}
}
@@ -67,24 +67,6 @@
}
}
&.align-items--flex-start {
align-items: flex-start;
}
.grow {
flex-grow: 1;
}
.do-not-shrink {
flex-shrink: 0;
}
.do-not-overflow {
min-width: 0;
flex-shrink: 1;
max-width: 100%;
}
.full-width {
width: 100%;
}
@@ -94,14 +76,21 @@ main.main {
min-width: 0;
max-width: 100%;
flex-grow: 1;
display: flex;
flex-direction: column;
gap: var(--section-separation);
@include respond(md) {
padding-top: var(--main-top-padding);
}
}
.main-container {
min-height: 100vh;
align-items: flex-start;
padding: 0 15px;
column-gap: var(--section-separation);
gap: var(--section-separation);
padding-top: var(--main-top-padding);
@include respond(md) {
padding: 0 20px;
+21 -23
View File
@@ -2,6 +2,7 @@
.article-list {
display: flex;
flex-direction: column;
gap: var(--section-separation);
article {
display: flex;
@@ -17,10 +18,6 @@
box-shadow: var(--shadow-l2);
}
&:not(:last-of-type) {
margin-bottom: var(--section-separation);
}
.article-image {
img {
width: 100%;
@@ -52,13 +49,13 @@
display: flex;
flex-direction: column;
justify-content: center;
padding: var(--card-padding);
gap: 15px;
}
.article-title {
font-weight: 600;
margin: 10px 0;
margin: 0;
color: var(--card-text-color-main);
font-size: 2.2rem;
@@ -73,52 +70,58 @@
color: var(--card-text-color-main);
}
}
& + .article-subtitle {
margin-top: 0;
}
}
.article-subtitle {
font-weight: normal;
color: var(--card-text-color-secondary);
margin: 5px 0;
line-height: 1.5;
margin: 0;
font-size: 1.75rem;
@include respond(xl) {
font-size: 2rem;
}
}
.article-time {
.article-title-wrapper {
display: flex;
flex-direction: column;
gap: 8px;
}
.article-time,
.article-translations {
display: flex;
align-items: center;
color: var(--card-text-color-tertiary);
gap: 15px;
margin-top: 10px;
flex-wrap: wrap;
svg {
vertical-align: middle;
margin-right: 15px;
width: 20px;
height: 20px;
stroke-width: 1.33;
}
time {
time,
a {
font-size: 1.4rem;
color: var(--card-text-color-tertiary);
}
& > div {
display: inline-flex;
align-items: center;
gap: 15px;
}
}
.article-category,
.article-tags {
display: flex;
gap: 10px;
a {
color: var(--accent-color-text);
background-color: var(--accent-color);
@@ -126,8 +129,6 @@
border-radius: var(--tag-border-radius);
display: inline-block;
font-size: 1.4rem;
margin-right: 10px;
margin-bottom: 10px;
transition: background-color 0.5s ease;
&:hover {
@@ -148,15 +149,12 @@
--image-size: 60px;
}
& + .pagination {
margin-top: var(--section-separation);
}
article {
& > a {
display: flex;
align-items: center;
padding: var(--small-card-padding);
gap: 15px;
}
&:not(:last-of-type) {
@@ -166,8 +164,8 @@
.article-details {
flex-grow: 1;
padding: 0;
padding-right: 15px;
min-height: var(--image-size);
gap: 10px;
}
.article-title {
+14 -1
View File
@@ -1,7 +1,6 @@
html {
font-size: 62.5%;
overflow-y: scroll;
scroll-behavior: smooth;
}
* {
@@ -23,3 +22,17 @@ body {
scrollbar-color: var(--scrollbar-thumb) transparent;
}
/**/
/* scrollbar styles for Chromium */
::-webkit-scrollbar {
height: auto;
}
::-webkit-scrollbar-thumb {
background-color: var(--scrollbar-thumb);
}
::-webkit-scrollbar-track {
background-color: transparent;
}
/**/
-1
View File
@@ -2,7 +2,6 @@ footer.site-footer {
padding: 20px 0 var(--section-separation) 0;
font-size: 1.4rem;
line-height: 1.75;
margin-top: var(--section-separation);
&:before {
content: "";
@@ -1,3 +0,0 @@
.archives-group {
margin-bottom: var(--section-separation);
}
+86 -108
View File
@@ -13,10 +13,6 @@
box-shadow: var(--shadow-l1);
overflow: hidden;
&.main-article {
margin-bottom: var(--section-separation);
}
.article-header {
.article-image {
img {
@@ -57,11 +53,11 @@
display: flex;
align-items: center;
font-size: 1.4rem;
gap: 15px;
svg {
width: 20px;
height: 20px;
margin-right: 15px;
stroke-width: 1.33;
}
}
@@ -122,69 +118,6 @@
}
}
.article-page.has-toc {
scroll-behavior: smooth;
.left-sidebar {
display: none;
}
.right-sidebar {
width: 100%;
padding: 0;
display: none;
@include respond(xl) {
display: block;
top: var(--main-top-padding);
}
}
#article-toolbar {
display: block;
@include respond(md) {
padding: 0;
}
@include respond(xl) {
margin-top: 0;
position: sticky;
top: var(--main-top-padding);
flex-shrink: 1;
a {
background: transparent;
box-shadow: none;
border: 1px solid var(--body-text-color);
width: 100%;
margin-right: 0;
svg {
flex-shrink: 0;
}
}
}
}
.main-container {
align-items: start;
flex-direction: column;
@include respond(xl) {
flex-direction: row;
}
}
.main {
padding-top: 0;
@include respond(xl) {
padding-top: var(--main-top-padding);
}
}
}
.widget--toc {
background-color: var(--card-background);
border-radius: var(--card-border-radius);
@@ -194,6 +127,10 @@
color: var(--card-text-color-main);
overflow: hidden;
::-webkit-scrollbar-thumb {
background-color: var(--card-separator-color);
}
#TableOfContents {
overflow-x: auto;
max-height: 75vh;
@@ -208,7 +145,7 @@
list-style-type: none;
counter-reset: item;
li:before {
li a::before {
counter-increment: item;
content: counters(item, ".") ". ";
font-weight: bold;
@@ -221,7 +158,7 @@
}
li {
margin: 15px 20px;
margin: 15px 0 15px 20px;
padding: 5px;
& > ol,
@@ -235,11 +172,39 @@
}
}
}
li.active-class > a {
border-left: var(--heading-border-size) solid var(--accent-color);
font-weight: bold;
}
}
.related-contents--wrapper {
margin-bottom: var(--section-separation);
ul li.active-class > a {
display: block;
}
@function repeat($str, $n) {
$result: "";
@for $_ from 0 to $n {
$result: $result + $str;
}
@return $result;
}
// Support up to 6 levels of indentation for lists in ToCs
@for $i from 0 to 5 {
& > ul #{repeat("> li > ul", $i)} > li.active-class > a {
$n: 25 + $i * 35;
margin-left: calc(-#{$n}px - 1em);
padding-left: calc(#{$n}px + 1em - var(--heading-border-size));
}
& > ol #{repeat("> li > ol", $i)} > li.active-class > a {
$n: 9 + $i * 35;
margin-left: calc(-#{$n}px - 1em);
padding-left: calc(#{$n}px + 1em - var(--heading-border-size));
display: block;
}
}
}
}
.related-contents {
@@ -287,9 +252,9 @@
h4,
h5,
h6 {
margin-left: calc((var(--card-padding)) * -1);
padding-left: calc(var(--card-padding) - var(--heading-border-size));
border-left: var(--heading-border-size) solid var(--accent-color);
margin-inline-start: calc((var(--card-padding)) * -1);
padding-inline-start: calc(var(--card-padding) - var(--heading-border-size));
border-inline-start: var(--heading-border-size) solid var(--accent-color);
}
figure {
@@ -304,7 +269,7 @@
blockquote {
position: relative;
margin: 1.5em 0;
border-left: var(--blockquote-border-size) solid var(--card-separator-color);
border-inline-start: var(--blockquote-border-size) solid var(--card-separator-color);
padding: 15px calc(var(--card-padding) - var(--blockquote-border-size));
background-color: var(--blockquote-background-color);
}
@@ -332,13 +297,10 @@
flex-direction: row;
justify-content: center;
margin: 1.5em 0;
gap: 10px;
figure {
margin: 0;
& + figure {
margin-left: 10px;
}
}
}
@@ -351,7 +313,10 @@
line-height: 1.428571429;
word-break: break-all;
padding: var(--card-padding);
// keep Codeblocks LTR
[dir="rtl"] & {
direction: ltr;
}
code {
color: unset;
border: none;
@@ -360,6 +325,44 @@
}
}
.highlight {
background-color: var(--pre-background-color);
padding: var(--card-padding);
position: relative;
&:hover {
.copyCodeButton {
opacity: 1;
}
}
// keep Codeblocks LTR
[dir="rtl"] & {
direction: ltr;
}
pre {
margin: initial;
padding: 0;
margin: 0;
width: auto;
}
}
.copyCodeButton {
position: absolute;
top: calc(var(--card-padding));
right: calc(var(--card-padding));
background: var(--card-background);
border: none;
box-shadow: var(--shadow-l2);
border-radius: var(--tag-border-radius);
padding: 8px 16px;
color: var(--card-text-color-main);
cursor: pointer;
font-size: 14px;
opacity: 0;
transition: opacity 0.3s ease;
}
.table-wrapper {
padding: 0 var(--card-padding);
overflow-x: auto;
@@ -414,6 +417,7 @@
/// Negative margins
blockquote,
figure,
.highlight,
pre,
.gallery,
.video-wrapper,
@@ -423,30 +427,4 @@
margin-right: calc((var(--card-padding)) * -1);
width: calc(100% + var(--card-padding) * 2);
}
.highlight {
position: relative;
&:hover {
.copyCodeButton {
opacity: 1;
}
}
}
.copyCodeButton {
position: absolute;
top: calc(var(--card-padding));
right: 0;
background: var(--card-background);
border: none;
box-shadow: var(--shadow-l2);
border-radius: var(--tag-border-radius);
padding: 8px 16px;
color: var(--card-text-color-main);
cursor: pointer;
font-size: 14px;
opacity: 0;
transition: opacity 0.3s ease;
}
}
+4 -8
View File
@@ -3,21 +3,16 @@
background-color: var(--card-background);
padding: var(--small-card-padding);
box-shadow: var(--shadow-l1);
margin-bottom: var(--section-separation);
display: flex;
align-items: center;
gap: 20px;
--separation: 15px;
.section-term {
font-size: 2.2rem;
margin: 0;
margin-top: calc(var(--separation) / 2);
color: var(--card-text-color-main);
& + .section-description {
margin-top: var(--separation);
}
}
.section-description {
@@ -29,7 +24,9 @@
.section-details {
flex-grow: 1;
margin-right: 20px;
display: flex;
flex-direction: column;
gap: 8px;
}
.section-image {
@@ -49,7 +46,6 @@
}
.subsection-list {
margin-bottom: var(--section-separation);
overflow-x: auto;
.article-list--tile {
+3 -3
View File
@@ -1,5 +1,4 @@
.search-form {
margin-bottom: var(--section-separation);
position: relative;
--button-size: 80px;
@@ -25,7 +24,7 @@
label {
position: absolute;
top: 15px;
left: 20px;
inset-inline-start: 20px;
font-size: 1.4rem;
color: var(--card-text-color-tertiary);
}
@@ -52,7 +51,7 @@
button {
position: absolute;
right: 0;
inset-inline-end: 0;
top: 0;
height: 100%;
width: var(--button-size);
@@ -79,4 +78,5 @@
height: 20px;
}
}
}
+33 -24
View File
@@ -101,11 +101,16 @@
background: none;
border: none;
position: absolute;
right: 30px;
top: 30px;
right: 0;
top: 0;
z-index: 2;
cursor: pointer;
[dir="rtl"] & {
left: 0;
right: auto;
}
@include respond(md) {
display: none;
}
@@ -125,21 +130,31 @@
.menu {
padding-left: 0;
list-style: none;
display: flex;
flex-direction: column;
overflow-y: auto;
flex-grow: 1;
font-size: 1.4rem;
background-color: var(--card-background);
padding: 15px 0;
box-shadow: var(--shadow-l1);
display: none;
margin: 0 calc(var(--container-padding) * -1);
margin: 0 -15px;
padding: 30px 30px;
@include respond(xl) {
padding: 15px 0;
}
&,
.menu-bottom-section {
gap: 30px;
@include respond(xl) {
gap: 25px;
}
}
&.show {
display: block;
display: flex;
}
@include respond(md) {
@@ -149,34 +164,19 @@
padding: 0;
box-shadow: none;
margin: 0;
margin-top: var(--sidebar-element-separation);
}
@include respond(xl) {
margin-top: 30px;
}
li {
position: relative;
vertical-align: middle;
padding: 10px 30px;
&:not(:last-of-type) {
margin-bottom: 15px;
@include respond(xl) {
margin-bottom: 20px;
}
}
padding: 0;
@include respond(md) {
width: 100%;
padding: 10px 0;
}
svg {
stroke-width: 1.33;
margin-right: 40px;
width: 20px;
height: 20px;
@@ -187,6 +187,7 @@
display: inline-flex;
align-items: center;
color: var(--body-text-color);
gap: var(--menu-icon-separation);
}
span {
@@ -200,11 +201,19 @@
}
}
}
.menu-bottom-section {
margin-top: auto;
display: flex;
flex-direction: column;
width: 100%;
}
}
.social-menu {
list-style: none;
padding: 0%;
padding: 0;
margin: 0;
display: flex;
flex-direction: row;
gap: 10px;
-1
View File
@@ -5,7 +5,6 @@
border-radius: var(--card-border-radius);
overflow: hidden;
flex-wrap: wrap;
margin: var(--section-separation) 0;
.page-link {
padding: 16px 32px;
+81 -43
View File
@@ -11,13 +11,15 @@
flex-direction: column;
flex-shrink: 0;
align-self: stretch;
width: 100%;
padding: 30px 0 15px 0;
gap: var(--sidebar-element-separation);
max-width: none;
width: 100%;
position: relative;
--sidebar-avatar-size: 120px;
--sidebar-avatar-size: 100px;
--sidebar-element-separation: 20px;
--emoji-size: 40px;
--emoji-font-size: 20px;
@include respond(md) {
width: auto;
@@ -27,18 +29,49 @@
}
@include respond(2xl) {
--sidebar-avatar-size: 140px;
--sidebar-avatar-size: 120px;
--sidebar-element-separation: 25px;
--emoji-size: 40px;
}
&.sticky {
top: 0;
}
&.compact {
--sidebar-avatar-size: 80px;
--emoji-size: 30px;
--emoji-font-size: 15px;
header {
@include respond(lg) {
flex-direction: row;
}
.site-meta {
gap: 5px;
}
.site-name {
font-size: 1.4rem;
@include respond(2xl) {
font-size: 1.75rem;
}
}
.site-description {
font-size: 1.4rem;
}
}
}
}
.right-sidebar {
flex-shrink: 0;
width: 100%;
display: none;
flex-direction: column;
gap: var(--widget-separation);
&.sticky {
top: 0;
@@ -49,11 +82,12 @@
}
}
.site-info {
.sidebar header {
z-index: 1;
transition: box-shadow 0.5s ease;
padding: 15px;
display: flex;
flex-direction: column;
gap: var(--sidebar-element-separation);
@include respond(md) {
padding: 0;
@@ -64,8 +98,7 @@
margin: 0;
width: var(--sidebar-avatar-size);
height: var(--sidebar-avatar-size);
margin-bottom: var(--sidebar-element-separation);
flex-shrink: 0;
.site-logo {
width: 100%;
@@ -76,58 +109,44 @@
.emoji {
position: absolute;
width: 40px;
height: 40px;
line-height: 40px;
width: var(--emoji-size);
height: var(--emoji-size);
line-height: var(--emoji-size);
border-radius: 100%;
bottom: 0;
right: 0;
text-align: center;
font-size: 20px;
font-size: var(--emoji-font-size);
background-color: var(--card-background);
box-shadow: var(--shadow-l2);
}
}
@include respond(2xl) {
width: 50px;
height: 50px;
line-height: 50px;
}
}
.site-meta {
display: flex;
flex-direction: column;
gap: 10px;
justify-content: center;
}
.site-name {
color: var(--accent-color);
margin: 0;
font-size: 1.8rem;
@include respond(2xl) {
font-size: 2rem;
}
}
.site-description {
color: var(--body-text-color);
font-weight: normal;
margin: 10px 0;
font-size: 1.6rem;
@include respond(2xl) {
font-size: 1.8rem;
}
}
}
.sidebar {
.widget {
margin-bottom: var(--section-separation);
.site-description {
color: var(--body-text-color);
font-weight: normal;
margin: 0;
font-size: 1.4rem;
&:not(:last-of-type):after {
content: "";
width: 100px;
height: 2px;
background-color: var(--body-text-color);
display: block;
margin-top: var(--section-separation);
@include respond(2xl) {
font-size: 1.6rem;
}
}
}
@@ -153,8 +172,27 @@
display: flex;
align-items: center;
cursor: pointer;
gap: var(--menu-icon-separation);
.icon-tabler-toggle-right {
display: none;
}
}
#i18n-switch {
color: var(--body-text-color);
display: inline-flex;
align-content: center;
gap: var(--menu-icon-separation);
select {
border: 0;
background-color: transparent;
color: var(--body-text-color);
option {
color: var(--card-text-color-main);
background-color: var(--card-background);
}
}
}
+4 -3
View File
@@ -1,4 +1,7 @@
.widget {
display: flex;
flex-direction: column;
.widget-icon {
svg {
width: 32px;
@@ -14,16 +17,14 @@
.tagCloud-tags {
display: flex;
flex-wrap: wrap;
gap: 10px;
a {
background: var(--card-background);
box-shadow: var(--shadow-l1);
border-radius: var(--tag-border-radius);
padding: 8px 20px;
color: var(--card-text-color-main);
margin-bottom: 10px;
margin-right: 5px;
font-size: 1.4rem;
transition: box-shadow 0.3s ease;
-1
View File
@@ -19,7 +19,6 @@
@import "partials/pagination.scss";
@import "partials/sidebar.scss";
@import "partials/base.scss";
@import "partials/layout/archives.scss";
@import "partials/layout/article.scss";
@import "partials/layout/list.scss";
@import "partials/layout/404.scss";
+19 -16
View File
@@ -1,26 +1,11 @@
$defaultTagBackgrounds: #8ea885, #df7988, #0177b8, #ffb900, #6b69d6;
$defaultTagColors: #fff, #fff, #fff, #fff, #fff;
[data-scheme="light"] {
--pre-text-color: #272822;
--pre-background-color: #fafafa;
@import "partials/highlight/light.scss";
}
[data-scheme="dark"] {
color-scheme: dark;
--pre-text-color: #f8f8f2;
--pre-background-color: #272822;
@import "partials/highlight/dark.scss";
}
/*
* Global style
*/
:root {
@include respond(md) {
--main-top-padding: 35px;
}
@include respond(xl) {
--main-top-padding: 50px;
@@ -46,7 +31,7 @@ $defaultTagColors: #fff, #fff, #fff, #fff, #fff;
--accent-color-darker: #bdc3c7;
--accent-color-text: #000;
--body-text-color: rgba(255, 255, 255, 0.7);
--scrollbar-thumb: #424242;
--scrollbar-thumb: hsl(0, 0%, 40%);
--scrollbar-track: var(--body-background);
}
}
@@ -160,3 +145,21 @@ $defaultTagColors: #fff, #fff, #fff, #fff, #fff;
--shadow-l4: 0px 24px 32px rgba(0, 0, 0, 0.04), 0px 16px 24px rgba(0, 0, 0, 0.04), 0px 4px 8px rgba(0, 0, 0, 0.04),
0px 0px 1px rgba(0, 0, 0, 0.04);
}
[data-scheme="light"] {
--pre-text-color: #272822;
--pre-background-color: #fafafa;
@import "partials/highlight/light.scss";
}
[data-scheme="dark"] {
--pre-text-color: #f8f8f2;
--pre-background-color: #272822;
@import "partials/highlight/dark.scss";
}
:root {
--menu-icon-separation: 40px;
--container-padding: 15px;
--widget-separation: var(--section-separation);
}
+54
View File
@@ -57,6 +57,60 @@ class StackGallery {
}
public static createGallery(container: HTMLElement) {
/// The process of wrapping image with figure tag is done using JavaScript instead of only Hugo markdown render hook
/// because it can not detect whether image is being wrapped by a link or not
/// and it lead to a invalid HTML construction (<a><figure><img></figure></a>)
const images = container.querySelectorAll('img.gallery-image');
for (const img of Array.from(images)) {
/// Images are wrapped with figure tag if the paragraph has only images without texts
/// This is done to allow inline images within paragraphs
const paragraph = img.closest('p');
if (!paragraph || !container.contains(paragraph)) continue;
if (paragraph.textContent.trim() == '') {
/// Once we insert figcaption, this check no longer works
/// So we add a class to paragraph to mark it
paragraph.classList.add('no-text');
}
let isNewLineImage = paragraph.classList.contains('no-text');
if (!isNewLineImage) continue;
const hasLink = img.parentElement.tagName == 'A';
let el: HTMLElement = img;
/// Wrap image with figure tag, with flex-grow and flex-basis values extracted from img's data attributes
const figure = document.createElement('figure');
figure.style.setProperty('flex-grow', img.getAttribute('data-flex-grow') || '1');
figure.style.setProperty('flex-basis', img.getAttribute('data-flex-basis') || '0');
if (hasLink) {
/// Wrap <a> if it exists
el = img.parentElement;
}
el.parentElement.insertBefore(figure, el);
figure.appendChild(el);
/// Add figcaption if it exists
if (img.hasAttribute('alt')) {
const figcaption = document.createElement('figcaption');
figcaption.innerText = img.getAttribute('alt');
figure.appendChild(figcaption);
}
/// Wrap img tag with <a> tag if image was not wrapped by <a> tag
if (!hasLink) {
figure.className = 'gallery-image';
const a = document.createElement('a');
a.href = img.src;
a.setAttribute('target', '_blank');
img.parentNode.insertBefore(a, img);
a.appendChild(img);
}
}
const figuresEl = container.querySelectorAll('figure.gallery-image');
let currentGallery = [];
+11 -6
View File
@@ -10,6 +10,8 @@ import { getColor } from 'ts/color';
import menu from 'ts/menu';
import createElement from 'ts/createElement';
import StackColorScheme from 'ts/colorScheme';
import { setupScrollspy } from 'ts/scrollspy';
import { setupSmoothAnchors } from "ts/smoothAnchors";
let Stack = {
init: () => {
@@ -21,6 +23,8 @@ let Stack = {
const articleContent = document.querySelector('.article-content') as HTMLElement;
if (articleContent) {
new StackGallery(articleContent);
setupSmoothAnchors();
setupScrollspy();
}
/**
@@ -58,20 +62,21 @@ let Stack = {
/**
* Add copy button to code block
*/
const codeBlocks = document.querySelectorAll('.article-content > div.highlight');
const highlights = document.querySelectorAll('.article-content div.highlight');
const copyText = `Copy`,
copiedText = `Copied!`;
codeBlocks.forEach(codeBlock => {
highlights.forEach(highlight => {
const copyButton = document.createElement('button');
copyButton.innerHTML = copyText;
copyButton.classList.add('copyCodeButton');
codeBlock.appendChild(copyButton);
highlight.appendChild(copyButton);
const pre = codeBlock.getElementsByTagName('pre');
const code = pre[0].textContent;
const codeBlock = highlight.querySelector('code[data-lang]');
if (!codeBlock) return;
copyButton.addEventListener('click', () => {
navigator.clipboard.writeText(code)
navigator.clipboard.writeText(codeBlock.textContent)
.then(() => {
copyButton.textContent = copiedText;
+131
View File
@@ -0,0 +1,131 @@
// Implements a scroll spy system for the ToC, displaying the current section with an indicator and scrolling to it when needed.
// Inspired from https://gomakethings.com/debouncing-your-javascript-events/
function debounced(func: Function) {
let timeout;
return () => {
if (timeout) {
window.cancelAnimationFrame(timeout);
}
timeout = window.requestAnimationFrame(() => func());
}
}
const headersQuery = ".article-content h1[id], .article-content h2[id], .article-content h3[id], .article-content h4[id], .article-content h5[id], .article-content h6[id]";
const tocQuery = "#TableOfContents";
const navigationQuery = "#TableOfContents li";
const activeClass = "active-class";
function scrollToTocElement(tocElement: HTMLElement, scrollableNavigation: HTMLElement) {
let textHeight = tocElement.querySelector("a").offsetHeight;
let scrollTop = tocElement.offsetTop - scrollableNavigation.offsetHeight / 2 + textHeight / 2 - scrollableNavigation.offsetTop;
if (scrollTop < 0) {
scrollTop = 0;
}
scrollableNavigation.scrollTo({ top: scrollTop, behavior: "smooth" });
}
type IdToElementMap = { [key: string]: HTMLElement };
function buildIdToNavigationElementMap(navigation: NodeListOf<Element>): IdToElementMap {
const sectionLinkRef: IdToElementMap = {};
navigation.forEach((navigationElement: HTMLElement) => {
const link = navigationElement.querySelector("a");
const href = link.getAttribute("href");
if (href.startsWith("#")) {
sectionLinkRef[href.slice(1)] = navigationElement;
}
});
return sectionLinkRef;
}
function computeOffsets(headers: NodeListOf<Element>) {
let sectionsOffsets = [];
headers.forEach((header: HTMLElement) => { sectionsOffsets.push({ id: header.id, offset: header.offsetTop }) });
sectionsOffsets.sort((a, b) => a.offset - b.offset);
return sectionsOffsets;
}
function setupScrollspy() {
let headers = document.querySelectorAll(headersQuery);
if (!headers) {
console.warn("No header matched query", headers);
return;
}
let scrollableNavigation = document.querySelector(tocQuery) as HTMLElement | undefined;
if (!scrollableNavigation) {
console.warn("No toc matched query", tocQuery);
return;
}
let navigation = document.querySelectorAll(navigationQuery);
if (!navigation) {
console.warn("No navigation matched query", navigationQuery);
return;
}
let sectionsOffsets = computeOffsets(headers);
// We need to avoid scrolling when the user is actively interacting with the ToC. Otherwise, if the user clicks on a link in the ToC,
// we would scroll their view, which is not optimal usability-wise.
let tocHovered: boolean = false;
scrollableNavigation.addEventListener("mouseenter", debounced(() => tocHovered = true));
scrollableNavigation.addEventListener("mouseleave", debounced(() => tocHovered = false));
let activeSectionLink: Element;
let idToNavigationElement: IdToElementMap = buildIdToNavigationElementMap(navigation);
function scrollHandler() {
let scrollPosition = document.documentElement.scrollTop || document.body.scrollTop;
let newActiveSection: HTMLElement | undefined;
// Find the section that is currently active.
// It is possible for no section to be active, so newActiveSection may be undefined.
sectionsOffsets.forEach((section) => {
if (scrollPosition >= section.offset - 20) {
newActiveSection = document.getElementById(section.id);
}
});
// Find the link for the active section. Once again, there are a few edge cases:
// - No active section = no link => undefined
// - No active section but the link does not exist in toc (e.g. because it is outside of the applicable ToC levels) => undefined
let newActiveSectionLink: HTMLElement | undefined
if (newActiveSection) {
newActiveSectionLink = idToNavigationElement[newActiveSection.id];
}
if (newActiveSection && !newActiveSectionLink) {
// The active section does not have a link in the ToC, so we can't scroll to it.
console.debug("No link found for section", newActiveSection);
} else if (newActiveSectionLink !== activeSectionLink) {
if (activeSectionLink)
activeSectionLink.classList.remove(activeClass);
if (newActiveSectionLink) {
newActiveSectionLink.classList.add(activeClass);
if (!tocHovered) {
// Scroll so that newActiveSectionLink is in the middle of scrollableNavigation, except when it's from a manual click (hence the tocHovered check)
scrollToTocElement(newActiveSectionLink, scrollableNavigation);
}
}
activeSectionLink = newActiveSectionLink;
}
}
window.addEventListener("scroll", debounced(scrollHandler));
// Resizing may cause the offset values to change: recompute them.
function resizeHandler() {
sectionsOffsets = computeOffsets(headers);
scrollHandler();
}
window.addEventListener("resize", debounced(resizeHandler));
}
export { setupScrollspy };
+34
View File
@@ -0,0 +1,34 @@
// Implements smooth scrolling when clicking on an anchor link.
// This is required instead of using modern CSS because Chromium does not currently support scrolling
// one element with scrollTo while another element is scrolled because of a click on a link. This would
// thus not work with the ToC scrollspy and e.g. footnotes.
// Here are additional links about this issue:
// - https://stackoverflow.com/questions/49318497/google-chrome-simultaneously-smooth-scrollintoview-with-more-elements-doesn
// - https://stackoverflow.com/questions/57214373/scrollintoview-using-smooth-function-on-multiple-elements-in-chrome
// - https://bugs.chromium.org/p/chromium/issues/detail?id=833617
// - https://bugs.chromium.org/p/chromium/issues/detail?id=1043933
// - https://bugs.chromium.org/p/chromium/issues/detail?id=1121151
const anchorLinksQuery = "a[href]";
function setupSmoothAnchors() {
document.querySelectorAll(anchorLinksQuery).forEach(aElement => {
let href = aElement.getAttribute("href");
if (!href.startsWith("#")) {
return;
}
aElement.addEventListener("click", clickEvent => {
clickEvent.preventDefault();
let targetId = aElement.getAttribute("href").substring(1);
// The replace done on ':' is here for footnotes, as this character would otherwise interfere when used as a CSS selector.
let target = document.querySelector(`#${targetId.replace(":", "\\:")}`) as HTMLElement;
window.history.pushState({}, "", aElement.getAttribute("href"));
scrollTo({ top: target.offsetTop, behavior: "smooth" });
});
});
}
export { setupSmoothAnchors };
+4 -10
View File
@@ -19,6 +19,7 @@ params:
lastUpdated: Jan 02, 2006 15:04 MST
sidebar:
compact: false
emoji:
subtitle:
avatar:
@@ -95,6 +96,7 @@ params:
darkTheme:
reactionsEnabled: 1
emitMetadata: 0
lang:
gitalk:
owner:
@@ -108,16 +110,8 @@ params:
id:
widgets:
enabled:
- search
- archives
- tag-cloud
archives:
limit: 5
tagCloud:
limit: 10
homepage: []
page: []
opengraph:
twitter:
+8
View File
@@ -36,3 +36,11 @@ KaTeX:
integrity: sha384-vZTG03m+2yp6N6BNi5iM4rW4oIwk5DfcNdFfxkk9ZWpDriOkXX8voJBFrAO7MpVl
type: script
defer: true
Cactus:
- src: https://latest.cactus.chat/cactus.js
integrity:
type: script
- src: https://latest.cactus.chat/style.css
integrity:
type: style
+40 -19
View File
@@ -4,6 +4,21 @@ theme: hugo-theme-stack
paginate: 5
title: Example Site
languages:
en:
languageName: English
title: Example Site
weight: 1
cn:
languageName: 中文
title: 演示站点
weight: 2
ar:
languageName: عربي
languagedirection: rtl
title: موقع تجريبي
weight: 3
# Change it to your Disqus shortname before using
disqusShortname: hugo-theme-stack
@@ -11,7 +26,7 @@ disqusShortname: hugo-theme-stack
googleAnalytics:
# Theme i18n support
# Available values: en, fr, id, ja, ko, pt-br, zh-cn, zh-tw, es, de, nl, it, th, el, uk
# Available values: en, fr, id, ja, ko, pt-br, zh-cn, zh-tw, es, de, nl, it, th, el, uk, ar
DefaultContentLanguage: en
# Set hasCJKLanguage to true if DefaultContentLanguage is in [zh-cn ja ko]
@@ -104,6 +119,12 @@ params:
path:
lang:
# See https://cactus.chat/docs/reference/web-client/#configuration for description of the various options
cactus:
defaultHomeserverUrl: "https://matrix.cactus.chat:8448"
serverName: "cactus.chat"
siteName: "" # You must insert a unique identifier here matching the one you registered (See https://cactus.chat/docs/getting-started/quick-start/#register-your-site)
giscus:
repo:
repoID:
@@ -125,18 +146,20 @@ params:
cusdis:
host:
id:
widgets:
enabled:
- search
- archives
- tag-cloud
archives:
homepage:
- type: search
- type: archives
params:
limit: 5
tagCloud:
- type: categories
params:
limit: 10
- type: tag-cloud
params:
limit: 10
page:
- type: toc
opengraph:
twitter:
@@ -169,15 +192,7 @@ params:
### See https://docs.stack.jimmycai.com/configuration/custom-menu.html
### To remove about, archive and search page menu item, remove `menu` field from their FrontMatter
menu:
main:
- identifier: home
name: Home
url: /
weight: -100
params:
### For demonstration purpose, the home link will be open in a new tab
newTab: true
icon: home
main: []
social:
- identifier: github
@@ -214,3 +229,9 @@ markup:
startLevel: 2
highlight:
noClasses: false
codeFences: true
guessSyntax: true
lineNoStart: 1
lineNos: true
lineNumbersInTable: true
tabWidth: 4
+8
View File
@@ -0,0 +1,8 @@
---
menu:
main:
name: 主页
weight: -100
params:
icon: home
---
+8
View File
@@ -0,0 +1,8 @@
---
menu:
main:
name: Home
weight: -100
params:
icon: home
---
@@ -0,0 +1,5 @@
---
title: 关于
---
This is a test page for i18n support.
@@ -162,3 +162,7 @@ X<sup>n</sup> + Y<sup>n</sup> = Z<sup>n</sup>
Press <kbd><kbd>CTRL</kbd>+<kbd>ALT</kbd>+<kbd>Delete</kbd></kbd> to end the session.
Most <mark>salamanders</mark> are nocturnal, and hunt for insects, worms, and other small creatures.
## Hyperlinked image
[![Google](https://www.google.com/images/branding/googlelogo/1x/googlelogo_light_color_272x92dp.png)](https://google.com)
@@ -0,0 +1,32 @@
+++
author = "Hugo Authors"
title = "مثال نص"
date = "2019-03-09"
description = "هذا النص هو مثال لنص يمكن أن يستبدل في نفس المساحة"
categories = [
"تجربة",
"تجربة مع فراغات"
]
tags = [
"ماركداون",
"نص",
"وسم مع فراغات"
]
image = "matt-le-SJSpo9hQf7s-unsplash.jpg"
+++
## فقرة 1
هذا النص هو مثال لنص يمكن أن يستبدل في نفس المساحة، لقد تم توليد هذا النص من [مولد النص العربى](https://colorslab.com/textgator/)، حيث يمكنك أن تولد مثل هذا النص أو العديد من النصوص الأخرى إضافة إلى زيادة عدد الحروف التى يولدها التطبيق.
إذا كنت تحتاج إلى عدد أكبر من الفقرات يتيح لك مولد النص العربى زيادة عدد الفقرات كما تريد، النص لن يبدو مقسما ولا يحوي أخطاء لغوية، مولد النص العربى مفيد لمصممي المواقع على وجه الخصوص، حيث يحتاج العميل فى كثير من الأحيان أن يطلع على صورة حقيقية لتصميم الموقع.
ومن هنا وجب على المصمم أن يضع نصوصا مؤقتة على التصميم ليظهر للعميل الشكل كاملاً،دور مولد النص العربى أن يوفر على المصمم عناء البحث عن نص بديل لا علاقة له بالموضوع الذى يتحدث عنه التصميم فيظهر بشكل لا يليق.
هذا النص يمكن أن يتم تركيبه على أي تصميم دون مشكلة فلن يبدو وكأنه نص منسوخ، غير منظم، غير منسق، أو حتى غير مفهوم. لأنه مازال نصاً بديلاً ومؤقتاً.
## فقرة 2
هذا النص هو مثال لنص يمكن أن يستبدل في نفس المساحة، لقد تم توليد هذا النص من [مولد النص العربى](https://colorslab.com/textgator/)، حيث يمكنك أن تولد مثل هذا النص أو العديد من النصوص الأخرى إضافة إلى زيادة عدد الحروف التى يولدها التطبيق.
إذا كنت تحتاج إلى عدد أكبر من الفقرات يتيح لك مولد النص العربى زيادة عدد الفقرات كما تريد، النص لن يبدو مقسما ولا يحوي أخطاء لغوية، مولد النص العربى مفيد لمصممي المواقع على وجه الخصوص، حيث يحتاج العميل فى كثير من الأحيان أن يطلع على صورة حقيقية لتصميم الموقع.
ومن هنا وجب على المصمم أن يضع نصوصا مؤقتة على التصميم ليظهر للعميل الشكل كاملاً،دور مولد النص العربى أن يوفر على المصمم عناء البحث عن نص بديل لا علاقة له بالموضوع الذى يتحدث عنه التصميم فيظهر بشكل لا يليق.
هذا النص يمكن أن يتم تركيبه على أي تصميم دون مشكلة فلن يبدو وكأنه نص منسوخ، غير منظم، غير منسق، أو حتى غير مفهوم. لأنه مازال نصاً بديلاً ومؤقتاً.
## تجربة RTL
كلمة 1 Text كلمة 2
@@ -36,3 +36,7 @@ Hugo ships with several [Built-in Shortcodes](https://gohugo.io/content-manageme
## bilibilibi Shortcode
{{< bilibili av498363026 >}}
## Gist Shortcode
{{< gist spf13 7896402 >}}
+2 -2
View File
@@ -1,3 +1,3 @@
module github.com/CaiJimmy/hugo-theme-stack
module github.com/CaiJimmy/hugo-theme-stack/v3
go 1.12
go 1.17
+70
View File
@@ -0,0 +1,70 @@
toggleMenu:
other: اخفي القائمة
darkMode:
other: الوضع الداكن
list:
page:
one: "{{ .Count }} صفحه"
other: "{{ .Count }} صفحات"
section:
other: قسم
subsection:
one: قسم فرعي
other: اقسام فرعية
article:
back:
other: خلف
tableOfContents:
other: جدول المحتويات
relatedContents:
other: محتوى مشابهه
lastUpdatedOn:
other: التعديل الاخير
readingTime:
one: "قرائة {{ .Count }} دقيقة"
other: "قرائة {{ .Count }} دقائق"
notFound:
title:
other: غير موجود
subtitle:
other: تعذر العثور على الصفحة المطلوبة.
widget:
archives:
title:
other: الارشيفات
more:
other: اكثر
tagCloud:
title:
other: وسوم
search:
title:
other: بحث
placeholder:
other: اكتب...
resultTitle:
other: "#PAGES_COUNT نتيجة (#TIME_SECONDS ثواني)"
footer:
builtWith:
other: "مبني بستخدام {{ .Generator }}"
designedBy:
other: "قالب {{ .Theme }} مصمم من {{ .DesignedBy }}"
+3
View File
@@ -51,6 +51,9 @@ widget:
tagCloud:
title:
other: Tags
categoriesCloud:
title:
other: Categories
search:
title:
+8 -13
View File
@@ -25,22 +25,17 @@
{{- end -}}
{{- end -}}
<figure
{{ if $galleryImage }}
class="gallery-image"
style="
flex-grow: {{ div (mul $image.Width 100) $image.Height }};
flex-basis: {{ div (mul $image.Width 240) $image.Height }}px"
{{ end }}>
<a href="{{ $Permalink }}" {{ if $galleryImage }}data-size="{{ $image.Width }}x{{ $image.Height }}"{{ end }}>
<img src="{{ $Permalink }}"
<img src="{{ $Permalink }}"
{{ with $Width }}width="{{ . }}"{{ end }}
{{ with $Height }}height="{{ . }}"{{ end }}
{{ with $Srcset }}srcset="{{ . }}"{{ end }}
loading="lazy"
{{ with $alt }}alt="{{ . }}"{{ end }}>
</a>
{{ with $alt }}
<figcaption>{{ . | markdownify }}</figcaption>
alt="{{ . }}"
{{ end }}
</figure>
{{ if $galleryImage }}
class="gallery-image"
data-flex-grow="{{ div (mul $image.Width 100) $image.Height }}"
data-flex-basis="{{ div (mul $image.Width 240) $image.Height }}px"
{{ end }}
>
+2
View File
@@ -1,5 +1,6 @@
{{ define "body-class" }}template-archives{{ end }}
{{ define "main" }}
<header>
{{- $taxonomy := $.Site.GetPage "taxonomyTerm" "categories" -}}
{{- $terms := $taxonomy.Pages -}}
{{ if $terms }}
@@ -12,6 +13,7 @@
</div>
</div>
{{ end }}
</header>
{{ $pages := where .Site.RegularPages "Type" "in" .Site.Params.mainSections }}
{{ $notHidden := where .Site.RegularPages "Params.hidden" "!=" true }}
+3 -2
View File
@@ -1,12 +1,13 @@
<!DOCTYPE html>
<html lang="{{ .Site.LanguageCode }}">
<html lang="{{ .Site.LanguageCode }}" dir="{{ default `ltr` .Language.LanguageDirection }}">
<head>
{{- partial "head/head.html" . -}}
{{- block "head" . -}}{{ end }}
</head>
<body class="{{ block `body-class` . }}{{ end }}">
{{- partial "head/colorScheme" . -}}
<div class="container main-container flex {{ block `container-class` . }}on-phone--column {{ if .Site.Params.widgets.enabled }}extended{{ else }}compact{{ end }}{{ end }}">
{{- $hasWidget := default (gt (len .Site.Params.widgets.homepage) 0) (.Scratch.Get "hasWidget") -}}
<div class="container main-container flex on-phone--column {{ if $hasWidget }}extended{{ else }}compact{{ end }}">
{{- block "left-sidebar" . -}}
{{ partial "sidebar/left.html" . }}
{{- end -}}
+5 -1
View File
@@ -1,4 +1,5 @@
{{ define "main" }}
<header>
<h3 class="section-title">
{{ if eq .Parent (.GetPage "/") }}
{{ T "list.section" }}
@@ -41,6 +42,7 @@
</div>
{{ end }}
</div>
</header>
{{- $subsections := .Sections -}}
{{- $pages := .Pages | complement $subsections -}}
@@ -53,6 +55,7 @@
{{- end -}}
{{- with $subsections -}}
<aside>
<h2 class="section-title">{{ T "list.subsection" (len $subsections) }}</h2>
<div class="subsection-list">
<div class="article-list--tile">
@@ -61,6 +64,7 @@
{{ end }}
</div>
</div>
</aside>
{{- end -}}
{{/* List only pages that are not a subsection */}}
@@ -77,5 +81,5 @@
{{ end }}
{{ define "right-sidebar" }}
{{ partialCached "sidebar/right.html" . }}
{{ partial "sidebar/right.html" (dict "Context" . "Scope" "homepage") }}
{{ end }}
+11 -5
View File
@@ -1,9 +1,15 @@
{{- $pages := where .Site.RegularPages "Type" "in" .Site.Params.mainSections -}}
{{- $notHidden := where .Site.RegularPages "Params.hidden" "!=" true -}}
{{- $filtered := ($pages | intersect $notHidden) -}}
{{- $pctx := . -}}
{{- if .IsHome -}}{{ $pctx = .Site }}{{- end -}}
{{- $pages := slice -}}
{{- if or $.IsHome $.IsSection -}}
{{- $pages = $pctx.RegularPages -}}
{{- else -}}
{{- $pages = $pctx.Pages -}}
{{- end -}}
{{- $pages := where $pages "Params.hidden" "!=" true -}}
{{- $limit := .Site.Config.Services.RSS.Limit -}}
{{- if ge $limit 1 -}}
{{- $filtered = $filtered | first $limit -}}
{{- $pages = $pages | first $limit -}}
{{- end -}}
{{- printf "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>" | safeHTML }}
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
@@ -20,7 +26,7 @@
{{- with .OutputFormats.Get "RSS" -}}
{{ printf "<atom:link href=%q rel=\"self\" type=%q />" .Permalink .MediaType | safeHTML }}
{{- end -}}
{{ range $filtered }}
{{ range $pages }}
{{- $content := safeHTML (.Summary | html) -}}
{{- if .Site.Params.rssFullContent -}}
{{- $content = safeHTML (.Content | html) -}}
+22 -37
View File
@@ -1,15 +1,26 @@
{{ define "body-class" }}
{{ $TOCEnabled := default (default false .Site.Params.article.toc) .Params.toc }}
{{- .Scratch.Set "hasTOC" (and (ge (len .TableOfContents) 100) $TOCEnabled) -}}
article-page {{ if (.Scratch.Get "hasTOC") }}has-toc{{ end }}
{{ end }}
article-page
{{/*
Enable the right sidebar if
- Widget different from 'TOC' is enabled
- TOC is enabled and not empty
*/}}
{{- $HasWidgetNotTOC := false -}}
{{- $TOCWidgetEnabled := false -}}
{{- range .Site.Params.widgets.page -}}
{{- if ne .type "toc" -}}
{{ $HasWidgetNotTOC = true -}}
{{- else -}}
{{ $TOCWidgetEnabled = true -}}
{{- end -}}
{{- end -}}
{{ define "container-class" }}
{{ if (.Scratch.Get "hasTOC") }}
extended
{{ else }}
on-phone--column {{ if .Site.Params.widgets.enabled }}extended{{ else }}compact{{ end }}
{{ end }}
{{- $TOCManuallyDisabled := eq .Params.toc false -}}
{{- $TOCEnabled := and (not $TOCManuallyDisabled) $TOCWidgetEnabled -}}
{{- $hasTOC := ge (len .TableOfContents) 100 -}}
{{- .Scratch.Set "TOCEnabled" (and $TOCEnabled $hasTOC) -}}
{{- .Scratch.Set "hasWidget" (or $HasWidgetNotTOC (and $TOCEnabled $hasTOC)) -}}
{{ end }}
{{ define "main" }}
@@ -30,32 +41,6 @@
{{ partialCached "article/components/photoswipe" . }}
{{ end }}
{{ define "left-sidebar" }}
{{ if (.Scratch.Get "hasTOC") }}
<div id="article-toolbar">
<a href="{{ .Site.BaseURL | relLangURL }}" class="back-home">
{{ (resources.Get "icons/back.svg").Content | safeHTML }}
<span>{{ T "article.back" }}</span>
</a>
</div>
{{ else }}
{{ partial "sidebar/left.html" . }}
{{ end }}
{{ end }}
{{ define "right-sidebar" }}
{{ if (.Scratch.Get "hasTOC") }}
<aside class="sidebar right-sidebar sticky">
<section class="widget archives">
<div class="widget-icon">
{{ partial "helper/icon" "hash" }}
</div>
<h2 class="widget-title section-title">{{ T "article.tableOfContents" }}</h2>
<div class="widget--toc">
{{ .TableOfContents }}
</div>
</section>
</aside>
{{ end }}
{{ if .Scratch.Get "hasWidget" }}{{ partial "sidebar/right.html" (dict "Context" . "Scope" "page") }}{{ end}}
{{ end }}
+1 -1
View File
@@ -15,5 +15,5 @@
{{ end }}
{{ define "right-sidebar" }}
{{ partial "sidebar/right.html" . }}
{{ partial "sidebar/right.html" (dict "Context" . "Scope" "homepage") }}
{{ end }}
+4 -2
View File
@@ -16,8 +16,10 @@
</button>
</form>
<h3 class="search-result--title section-title"></h3>
<div class="search-result--list article-list--compact"></div>
<div class="search-result">
<h3 class="search-result--title section-title"></h3>
<div class="search-result--list article-list--compact"></div>
</div>
<script>
window.searchResultTitleTemplate = "{{ T `search.resultTitle` }}"
@@ -9,6 +9,7 @@
</header>
{{ end }}
<div class="article-title-wrapper">
<h2 class="article-title">
<a href="{{ .RelPermalink }}">
{{- .Title -}}
@@ -20,6 +21,7 @@
{{ . }}
</h3>
{{ end }}
</div>
{{ if or (not .Date.IsZero) (.Site.Params.article.readingTime) }}
<footer class="article-time">
@@ -42,4 +44,15 @@
{{ end }}
</footer>
{{ end }}
{{ if .IsTranslated }}
<footer class="article-translations">
{{ partial "helper/icon" "language" }}
<div>
{{ range .Translations }}
<a href="{{ .Permalink }}" class="link">{{ .Language.LanguageName }}</a>
{{ end }}
</div>
</footer>
{{ end }}
</div>
@@ -1,6 +1,6 @@
{{ $related := (where (.Site.RegularPages.Related .) "Params.hidden" "!=" true) | first 5 }}
{{ with $related }}
<aside class="related-contents--wrapper">
{{ $related := (where (.Site.RegularPages.Related .) "Params.hidden" "!=" true) | first 5 }}
{{ with $related }}
<h2 class="section-title">{{ T "article.relatedContents" }}</h2>
<div class="related-contents">
<div class="flex article-list--tile">
@@ -9,5 +9,5 @@
{{ end }}
</div>
</div>
{{ end }}
</aside>
{{ end }}
@@ -0,0 +1,29 @@
{{- with .Site.Params.comments.cactus -}}
{{- partial "helper/external" (dict "Context" $ "Namespace" "Cactus") -}}
<style>
.cactus-editor-textarea {
color: var(--body-text-color);
}
.cactus-comment-header {
color: var(--card-text-color-main);
}
.cactus-message-text > p {
color: var(--body-text-color);
}
</style>
<div id="comment-section"></div>
<script>
initComments({
node: document.getElementById("comment-section"),
defaultHomeserverUrl: "{{ .defaultHomeserverUrl | safeJS }}",
serverName: "{{ .serverName }}",
siteName: "{{ .siteName }}",
commentSectionId: "{{ $.File.UniqueID }}"
})
</script>
{{- end -}}
+15 -15
View File
@@ -9,41 +9,41 @@
data-reactions-enabled="{{- default 1 .reactionsEnabled -}}"
data-emit-metadata="{{- default 0 .emitMetadata -}}"
data-theme="{{- default `light` .lightTheme -}}"
data-lang="{{- default `en` .lang -}}"
crossorigin="anonymous"
async
></script>
<script>
function setGiscusTheme(theme) {
let giscus = document.querySelector('iframe.giscus-frame');
let giscus = document.querySelector("iframe.giscus-frame");
if (giscus) {
giscus.contentWindow.postMessage(
{
giscus: {
setConfig: {
theme: theme
}
}
theme: theme,
},
},
},
"https://giscus.app"
);
};
};
}
}
(function(){
addEventListener('message', (e) => {
if (event.origin !== 'https://giscus.app') return;
handler()
(function () {
addEventListener("message", (e) => {
if (event.origin !== "https://giscus.app") return;
handler();
});
window.addEventListener('onColorSchemeChange', handler);
window.addEventListener("onColorSchemeChange", handler);
function handler() {
if (document.documentElement.dataset.scheme === "light") {
setGiscusTheme('{{- default "light" .lightTheme -}}');
} else {
setGiscusTheme('{{- default "dark_dimmed" .darkTheme -}}');
};
};
}());
}
}
})();
</script>
{{- end -}}
@@ -1,4 +1,4 @@
<script src="//cdn.jsdelivr.net/npm/[email protected]5/dist/twikoo.all.min.js"></script>
<script src="//cdn.jsdelivr.net/npm/[email protected]8/dist/twikoo.all.min.js"></script>
<div id="tcomment"></div>
<style>
.twikoo {
+1 -1
View File
@@ -1,4 +1,4 @@
{{- $ThemeVersion := "3.7.0" -}}
{{- $ThemeVersion := "3.9.0" -}}
<footer class="site-footer">
<section class="copyright">
&copy;
+1 -1
View File
@@ -8,7 +8,7 @@
integrity="{{ . }}"
{{- end -}}
crossorigin="anonymous"
defer="{{ default false .defer }}"
{{ if .defer }}defer{{ end }}
>
</script>
{{- else if eq .type "style" -}}
+19 -3
View File
@@ -1,11 +1,11 @@
<aside class="sidebar left-sidebar sticky">
<aside class="sidebar left-sidebar sticky {{ if .Site.Params.sidebar.compact }}compact{{ end }}">
<button class="hamburger hamburger--spin" type="button" id="toggle-menu" aria-label="{{ T `toggleMenu` }}">
<span class="hamburger-box">
<span class="hamburger-inner"></span>
</span>
</button>
<header class="site-info">
<header>
{{ with .Site.Params.sidebar.avatar }}
{{ if (default true .enabled) }}
<figure class="site-avatar">
@@ -31,8 +31,11 @@
{{ end }}
{{ end }}
<div class="site-meta">
<h1 class="site-name"><a href="{{ .Site.BaseURL | relLangURL }}">{{ .Site.Title }}</a></h1>
<h2 class="site-description">{{ .Site.Params.sidebar.subtitle }}</h2>
</div>
</header>
{{- with .Site.Menus.social -}}
<ol class="social-menu">
@@ -52,7 +55,6 @@
{{ end }}
</ol>
{{- end -}}
</header>
<ol class="menu" id="main-menu">
{{ $currentPage := . }}
@@ -73,6 +75,19 @@
</li>
{{ end }}
<div class="menu-bottom-section">
{{- $currentLanguageCode := .Language.Lang -}}
{{ with .Site.Home.AllTranslations }}
<li id="i18n-switch">
{{ partial "helper/icon" "language" }}
<select name="language" onchange="window.location.href = this.selectedOptions[0].value">
{{ range . }}
<option value="{{ .Permalink }}" {{ if eq .Language.Lang $currentLanguageCode }}selected{{ end }}>{{ .Language.LanguageName }}</option>
{{ end }}
</select>
</li>
{{ end }}
{{ if (default false .Site.Params.colorScheme.toggle) }}
<li id="dark-mode-toggle">
{{ partial "helper/icon" "toggle-left" }}
@@ -80,5 +95,6 @@
<span>{{ T "darkMode" }}</span>
</li>
{{ end }}
</div>
</ol>
</aside>
+9 -4
View File
@@ -1,8 +1,13 @@
{{ if .Site.Params.widgets.enabled }}
{{ $context := . }}
{{- $scope := default "homepage" .Scope -}}
{{- $context := .Context -}}
{{- with (index .Context.Site.Params.widgets $scope) -}}
<aside class="sidebar right-sidebar sticky">
{{ range $widget := .Site.Params.widgets.enabled }}
{{ partial (printf "widget/%s" $widget) $context }}
{{ range $widget := . }}
{{ if templates.Exists (printf "partials/widget/%s.html" .type) }}
{{ partial (printf "widget/%s" .type) (dict "Context" $context "Params" .params) }}
{{ else }}
{{ warnf "Widget %s not found" .type }}
{{ end }}
{{ end }}
</aside>
{{ end }}
+7 -5
View File
@@ -1,4 +1,6 @@
{{- $query := first 1 (where .Site.Pages "Layout" "==" "archives") -}}
{{- $query := first 1 (where .Context.Site.Pages "Layout" "==" "archives") -}}
{{- $context := .Context -}}
{{- $limit := default 5 .Params.limit -}}
{{- if $query -}}
{{- $archivesPage := index $query 0 -}}
<section class="widget archives">
@@ -7,17 +9,17 @@
</div>
<h2 class="widget-title section-title">{{ T "widget.archives.title" }}</h2>
{{ $pages := where .Site.RegularPages "Type" "in" .Site.Params.mainSections }}
{{ $notHidden := where .Site.RegularPages "Params.hidden" "!=" true }}
{{ $pages := where $context.Site.RegularPages "Type" "in" $context.Site.Params.mainSections }}
{{ $notHidden := where $context.Site.RegularPages "Params.hidden" "!=" true }}
{{ $filtered := ($pages | intersect $notHidden) }}
{{ $archives := $filtered.GroupByDate "2006" }}
<div class="widget-archive--list">
{{ range $index, $item := first (add .Site.Params.widgets.archives.limit 1) ($archives) }}
{{ range $index, $item := first (add $limit 1) ($archives) }}
{{- $id := lower (replace $item.Key " " "-") -}}
<div class="archives-year">
<a href="{{ $archivesPage.RelPermalink }}#{{ $id }}">
{{ if eq $index $.Site.Params.widgets.archives.limit }}
{{ if eq $index $limit }}
<span class="year">{{ T "widget.archives.more" }}</span>
{{ else }}
<span class="year">{{ .Key }}</span>
+16
View File
@@ -0,0 +1,16 @@
{{- $context := .Context -}}
{{- $limit := default 10 .Params.limit -}}
<section class="widget tagCloud">
<div class="widget-icon">
{{ partial "helper/icon" "categories" }}
</div>
<h2 class="widget-title section-title">{{ T "widget.categoriesCloud.title" }}</h2>
<div class="tagCloud-tags">
{{ range first $limit $context.Site.Taxonomies.categories.ByCount }}
<a href="{{ .Page.RelPermalink }}" class="font_size_{{ .Count }}">
{{ .Page.Title }}
</a>
{{ end }}
</div>
</section>
+1 -1
View File
@@ -1,4 +1,4 @@
{{- $query := first 1 (where .Site.Pages "Layout" "==" "search") -}}
{{- $query := first 1 (where .Context.Site.Pages "Layout" "==" "search") -}}
{{- if $query -}}
{{- $searchPage := index $query 0 -}}
<form action="{{ $searchPage.RelPermalink }}" class="search-form widget" {{ with .OutputFormats.Get "json" -}}data-json="{{ .Permalink }}" {{- end }}>
+3 -1
View File
@@ -1,3 +1,5 @@
{{- $context := .Context -}}
{{- $limit := default 10 .Params.limit -}}
<section class="widget tagCloud">
<div class="widget-icon">
{{ partial "helper/icon" "tag" }}
@@ -5,7 +7,7 @@
<h2 class="widget-title section-title">{{ T "widget.tagCloud.title" }}</h2>
<div class="tagCloud-tags">
{{ range first .Site.Params.widgets.tagCloud.limit .Site.Taxonomies.tags.ByCount }}
{{ range first $limit $context.Site.Taxonomies.tags.ByCount }}
<a href="{{ .Page.RelPermalink }}" class="font_size_{{ .Count }}">
{{ .Page.Title }}
</a>
+12
View File
@@ -0,0 +1,12 @@
{{ if (.Context.Scratch.Get "TOCEnabled") }}
<section class="widget archives">
<div class="widget-icon">
{{ partial "helper/icon" "hash" }}
</div>
<h2 class="widget-title section-title">{{ T "article.tableOfContents" }}</h2>
<div class="widget--toc">
{{ .Context.TableOfContents }}
</div>
</section>
{{ end }}