Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8f5164b5b9 | ||
|
|
07da61b1f2 | ||
|
|
76925213a3 | ||
|
|
0317e19ef2 | ||
|
|
863e6d4116 | ||
|
|
72629cf476 | ||
|
|
d455336d57 | ||
|
|
5449f786ac | ||
|
|
6f60f4f552 | ||
|
|
985af924e7 | ||
|
|
c122e5e9a1 | ||
|
|
15d2040f7e | ||
|
|
79e23544a9 | ||
|
|
c4e864a08d | ||
|
|
dbf4c2e58f | ||
|
|
47c19a0fbc | ||
|
|
0d0375a7fc | ||
|
|
86ad00cf8c | ||
|
|
e22664be13 | ||
|
|
d806226ec8 | ||
|
|
8abaa444c1 | ||
|
|
04cdbcfedf | ||
|
|
adf27aebf2 | ||
|
|
9dbc0a4f38 | ||
|
|
24cd07589b | ||
|
|
98923b1dd7 | ||
|
|
2712887c7c | ||
|
|
b3b8fa73ef | ||
|
|
26fb06951b | ||
|
|
4d552a9df5 | ||
|
|
0fbbc12949 | ||
|
|
4b0dbb4630 | ||
|
|
ce57ea915e | ||
|
|
9f36a956ca | ||
|
|
d75dbe2b6e | ||
|
|
88beecd101 | ||
|
|
67d5156507 | ||
|
|
6474b9dfd8 | ||
|
|
7dc5def217 | ||
|
|
2b40a32d47 |
@@ -1 +1,2 @@
|
||||
ko_fi: jimmycai
|
||||
github: CaiJimmy
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
public
|
||||
resources
|
||||
assets/jsconfig.json
|
||||
.hugo_build.lock
|
||||
@@ -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 |
@@ -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
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
/**/
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
|
||||
@@ -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 };
|
||||
@@ -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
@@ -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:
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
---
|
||||
menu:
|
||||
main:
|
||||
name: 主页
|
||||
weight: -100
|
||||
params:
|
||||
icon: home
|
||||
---
|
||||
@@ -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
|
||||
|
||||
[](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 >}}
|
||||
@@ -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
|
||||
|
||||
@@ -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 }}"
|
||||
@@ -51,6 +51,9 @@ widget:
|
||||
tagCloud:
|
||||
title:
|
||||
other: Tags
|
||||
categoriesCloud:
|
||||
title:
|
||||
other: Categories
|
||||
|
||||
search:
|
||||
title:
|
||||
|
||||
@@ -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 }}
|
||||
>
|
||||
@@ -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 }}
|
||||
|
||||
@@ -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 -}}
|
||||
|
||||
@@ -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 }}
|
||||
@@ -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) -}}
|
||||
@@ -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
@@ -15,5 +15,5 @@
|
||||
{{ end }}
|
||||
|
||||
{{ define "right-sidebar" }}
|
||||
{{ partial "sidebar/right.html" . }}
|
||||
{{ partial "sidebar/right.html" (dict "Context" . "Scope" "homepage") }}
|
||||
{{ end }}
|
||||
@@ -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 -}}
|
||||
@@ -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,4 +1,4 @@
|
||||
{{- $ThemeVersion := "3.7.0" -}}
|
||||
{{- $ThemeVersion := "3.9.0" -}}
|
||||
<footer class="site-footer">
|
||||
<section class="copyright">
|
||||
©
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
integrity="{{ . }}"
|
||||
{{- end -}}
|
||||
crossorigin="anonymous"
|
||||
defer="{{ default false .defer }}"
|
||||
{{ if .defer }}defer{{ end }}
|
||||
>
|
||||
</script>
|
||||
{{- else if eq .type "style" -}}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 }}
|
||||
@@ -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>
|
||||
|
||||
@@ -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,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 }}>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 }}
|
||||
Reference in New Issue
Block a user