mirror of
https://github.com/imfing/hextra.git
synced 2025-07-01 19:57:11 -04:00
Compare commits
42 Commits
v0.3.0
...
122-improv
Author | SHA1 | Date | |
---|---|---|---|
9fc253dff5 | |||
0125822785 | |||
1e1d1c8716 | |||
1048ee47d7 | |||
5842f893a3 | |||
78ce7c2f2e | |||
0652772c15 | |||
13e4eb3414 | |||
529fcd8a62 | |||
21a13c49f9 | |||
98d0a3dc73 | |||
24f3178ea8 | |||
230cc438b7 | |||
214cb7994f | |||
792ad4b569 | |||
97e6945c04 | |||
93cb788e52 | |||
88b0f1b2ab | |||
a31b46f5e3 | |||
6641d36b98 | |||
e42d01898a | |||
6cd4c55613 | |||
cb09b7ce1e | |||
96c6ff073f | |||
28a20e1e7e | |||
5f4c7423d0 | |||
2bc4ed19e3 | |||
8aa6439132 | |||
b7558aca44 | |||
55ff819dae | |||
924d8508d0 | |||
1b932f260a | |||
5768ed4695 | |||
f4cea168b1 | |||
e2d00fdcd0 | |||
103faa24f3 | |||
d1bed05843 | |||
2df3c563bf | |||
ec02eb34fe | |||
46dea718e6 | |||
adf5a113fc | |||
6a19ac31c0 |
40
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
40
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
---
|
||||||
|
name: Bug report
|
||||||
|
about: Create a report to help us improve
|
||||||
|
title: ''
|
||||||
|
labels: ''
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Description**
|
||||||
|
|
||||||
|
<!-- Provide a clear and concise description of the bug -->
|
||||||
|
|
||||||
|
**Steps To Reproduce**
|
||||||
|
|
||||||
|
1.
|
||||||
|
2.
|
||||||
|
3.
|
||||||
|
|
||||||
|
**Expected Behavior**
|
||||||
|
|
||||||
|
<!-- What should have happened? -->
|
||||||
|
|
||||||
|
**Actual Behavior**
|
||||||
|
|
||||||
|
<!-- What happened instead? -->
|
||||||
|
|
||||||
|
**Screenshots**
|
||||||
|
|
||||||
|
<!-- If applicable, add screenshots to help explain your problem -->
|
||||||
|
|
||||||
|
**Environment**
|
||||||
|
|
||||||
|
- Hugo Version: [e.g., 0.85.0]
|
||||||
|
- Browser/OS: [e.g., Chrome, MacOS]
|
||||||
|
- Theme Version: [e.g., v2.0]
|
||||||
|
|
||||||
|
**Additional Context**
|
||||||
|
|
||||||
|
<!-- Add any other context about the problem here -->
|
24
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
24
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
---
|
||||||
|
name: Feature request
|
||||||
|
about: Suggest an idea for this project
|
||||||
|
title: ''
|
||||||
|
labels: ''
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Feature Description**
|
||||||
|
|
||||||
|
<!-- Provide a clear and concise description of the feature -->
|
||||||
|
|
||||||
|
**Problem/Solution**
|
||||||
|
|
||||||
|
<!-- What problem will this feature solve? Or what new capability will it add? -->
|
||||||
|
|
||||||
|
**Alternatives Considered**
|
||||||
|
|
||||||
|
<!-- Have you considered any alternative solutions or workarounds? -->
|
||||||
|
|
||||||
|
**Additional Context**
|
||||||
|
|
||||||
|
<!-- Add any other context or screenshots about the feature request here -->
|
@ -697,6 +697,12 @@ video {
|
|||||||
.h-2 {
|
.h-2 {
|
||||||
height: 0.5rem;
|
height: 0.5rem;
|
||||||
}
|
}
|
||||||
|
.h-3 {
|
||||||
|
height: 0.75rem;
|
||||||
|
}
|
||||||
|
.h-3\.5 {
|
||||||
|
height: 0.875rem;
|
||||||
|
}
|
||||||
.h-4 {
|
.h-4 {
|
||||||
height: 1rem;
|
height: 1rem;
|
||||||
}
|
}
|
||||||
@ -941,6 +947,10 @@ video {
|
|||||||
--tw-border-opacity: 1;
|
--tw-border-opacity: 1;
|
||||||
border-color: rgb(229 231 235 / var(--tw-border-opacity));
|
border-color: rgb(229 231 235 / var(--tw-border-opacity));
|
||||||
}
|
}
|
||||||
|
.border-gray-500 {
|
||||||
|
--tw-border-opacity: 1;
|
||||||
|
border-color: rgb(107 114 128 / var(--tw-border-opacity));
|
||||||
|
}
|
||||||
.border-orange-100 {
|
.border-orange-100 {
|
||||||
--tw-border-opacity: 1;
|
--tw-border-opacity: 1;
|
||||||
border-color: rgb(255 237 213 / var(--tw-border-opacity));
|
border-color: rgb(255 237 213 / var(--tw-border-opacity));
|
||||||
@ -977,18 +987,18 @@ video {
|
|||||||
}
|
}
|
||||||
.bg-primary-100 {
|
.bg-primary-100 {
|
||||||
--tw-bg-opacity: 1;
|
--tw-bg-opacity: 1;
|
||||||
background-color: hsl(var(--primary-hue) 100% 94% / var(--tw-bg-opacity));
|
background-color: hsl(var(--primary-hue) var(--primary-saturation) 94% / var(--tw-bg-opacity));
|
||||||
}
|
}
|
||||||
.bg-primary-400 {
|
.bg-primary-400 {
|
||||||
--tw-bg-opacity: 1;
|
--tw-bg-opacity: 1;
|
||||||
background-color: hsl(var(--primary-hue) 100% 66% / var(--tw-bg-opacity));
|
background-color: hsl(var(--primary-hue) var(--primary-saturation) 66% / var(--tw-bg-opacity));
|
||||||
}
|
}
|
||||||
.bg-primary-600 {
|
.bg-primary-600 {
|
||||||
--tw-bg-opacity: 1;
|
--tw-bg-opacity: 1;
|
||||||
background-color: hsl(var(--primary-hue) 100% 45% / var(--tw-bg-opacity));
|
background-color: hsl(var(--primary-hue) var(--primary-saturation) 45% / var(--tw-bg-opacity));
|
||||||
}
|
}
|
||||||
.bg-primary-700\/5 {
|
.bg-primary-700\/5 {
|
||||||
background-color: hsl(var(--primary-hue) 100% 39% / 0.05);
|
background-color: hsl(var(--primary-hue) var(--primary-saturation) 39% / 0.05);
|
||||||
}
|
}
|
||||||
.bg-red-100 {
|
.bg-red-100 {
|
||||||
--tw-bg-opacity: 1;
|
--tw-bg-opacity: 1;
|
||||||
@ -1251,7 +1261,7 @@ video {
|
|||||||
}
|
}
|
||||||
.text-primary-800 {
|
.text-primary-800 {
|
||||||
--tw-text-opacity: 1;
|
--tw-text-opacity: 1;
|
||||||
color: hsl(var(--primary-hue) 100% 32% / var(--tw-text-opacity));
|
color: hsl(var(--primary-hue) var(--primary-saturation) 32% / var(--tw-text-opacity));
|
||||||
}
|
}
|
||||||
.text-red-900 {
|
.text-red-900 {
|
||||||
--tw-text-opacity: 1;
|
--tw-text-opacity: 1;
|
||||||
@ -1370,6 +1380,9 @@ video {
|
|||||||
.duration-200 {
|
.duration-200 {
|
||||||
transition-duration: 200ms;
|
transition-duration: 200ms;
|
||||||
}
|
}
|
||||||
|
.duration-75 {
|
||||||
|
transition-duration: 75ms;
|
||||||
|
}
|
||||||
.ease-in {
|
.ease-in {
|
||||||
transition-timing-function: cubic-bezier(0.4, 0, 1, 1);
|
transition-timing-function: cubic-bezier(0.4, 0, 1, 1);
|
||||||
}
|
}
|
||||||
@ -1426,7 +1439,7 @@ video {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
:is(html[class~="dark"] .content h2) {
|
:is(html[class~="dark"] .content h2) {
|
||||||
border-color: hsl(var(--primary-hue) 100% 94% / 0.1);
|
border-color: hsl(var(--primary-hue) var(--primary-saturation) 94% / 0.1);
|
||||||
--tw-text-opacity: 1;
|
--tw-text-opacity: 1;
|
||||||
color: rgb(241 245 249 / var(--tw-text-opacity));
|
color: rgb(241 245 249 / var(--tw-text-opacity));
|
||||||
}
|
}
|
||||||
@ -1492,9 +1505,13 @@ video {
|
|||||||
.content p:first-child {
|
.content p:first-child {
|
||||||
margin-top: 0px;
|
margin-top: 0px;
|
||||||
}
|
}
|
||||||
|
.content .not-prose p {
|
||||||
|
margin-top: 0px;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
.content a {
|
.content a {
|
||||||
--tw-text-opacity: 1;
|
--tw-text-opacity: 1;
|
||||||
color: hsl(var(--primary-hue) 100% 45% / var(--tw-text-opacity));
|
color: hsl(var(--primary-hue) var(--primary-saturation) 45% / var(--tw-text-opacity));
|
||||||
text-decoration-line: underline;
|
text-decoration-line: underline;
|
||||||
text-decoration-thickness: from-font;
|
text-decoration-thickness: from-font;
|
||||||
text-underline-position: from-font;
|
text-underline-position: from-font;
|
||||||
@ -1532,7 +1549,7 @@ video {
|
|||||||
margin-bottom: 1rem;
|
margin-bottom: 1rem;
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
border-radius: 0.75rem;
|
border-radius: 0.75rem;
|
||||||
background-color: hsl(var(--primary-hue) 100% 39% / 0.05);
|
background-color: hsl(var(--primary-hue) var(--primary-saturation) 39% / 0.05);
|
||||||
padding-top: 1rem;
|
padding-top: 1rem;
|
||||||
padding-bottom: 1rem;
|
padding-bottom: 1rem;
|
||||||
font-size: .9em;
|
font-size: .9em;
|
||||||
@ -1544,18 +1561,18 @@ video {
|
|||||||
|
|
||||||
.content pre:not(.code-block pre) {
|
.content pre:not(.code-block pre) {
|
||||||
border-width: 1px;
|
border-width: 1px;
|
||||||
border-color: hsl(var(--primary-hue) 100% 24% / 0.2);
|
border-color: hsl(var(--primary-hue) var(--primary-saturation) 24% / 0.2);
|
||||||
--tw-contrast: contrast(1.5);
|
--tw-contrast: contrast(1.5);
|
||||||
filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
|
filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
:is(html[class~="dark"] .content pre:not(.code-block pre)) {
|
:is(html[class~="dark"] .content pre:not(.code-block pre)) {
|
||||||
background-color: hsl(var(--primary-hue) 100% 77% / 0.1);
|
background-color: hsl(var(--primary-hue) var(--primary-saturation) 77% / 0.1);
|
||||||
}
|
}
|
||||||
@media (prefers-contrast: more) {
|
@media (prefers-contrast: more) {
|
||||||
|
|
||||||
:is(html[class~="dark"] .content pre:not(.code-block pre)) {
|
:is(html[class~="dark"] .content pre:not(.code-block pre)) {
|
||||||
border-color: hsl(var(--primary-hue) 100% 94% / 0.4);
|
border-color: hsl(var(--primary-hue) var(--primary-saturation) 94% / 0.4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.content code:not(.code-block code) {
|
.content code:not(.code-block code) {
|
||||||
@ -2151,7 +2168,7 @@ article details > summary::before {
|
|||||||
}
|
}
|
||||||
.code-block pre {
|
.code-block pre {
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
background-color: hsl(var(--primary-hue) 100% 39% / 0.05);
|
background-color: hsl(var(--primary-hue) var(--primary-saturation) 39% / 0.05);
|
||||||
font-size: .9em;
|
font-size: .9em;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
-webkit-font-smoothing: auto;
|
-webkit-font-smoothing: auto;
|
||||||
@ -2161,18 +2178,18 @@ article details > summary::before {
|
|||||||
|
|
||||||
.code-block pre {
|
.code-block pre {
|
||||||
border-width: 1px;
|
border-width: 1px;
|
||||||
border-color: hsl(var(--primary-hue) 100% 24% / 0.2);
|
border-color: hsl(var(--primary-hue) var(--primary-saturation) 24% / 0.2);
|
||||||
--tw-contrast: contrast(1.5);
|
--tw-contrast: contrast(1.5);
|
||||||
filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
|
filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
:is(html[class~="dark"] .code-block pre) {
|
:is(html[class~="dark"] .code-block pre) {
|
||||||
background-color: hsl(var(--primary-hue) 100% 77% / 0.1);
|
background-color: hsl(var(--primary-hue) var(--primary-saturation) 77% / 0.1);
|
||||||
}
|
}
|
||||||
@media (prefers-contrast: more) {
|
@media (prefers-contrast: more) {
|
||||||
|
|
||||||
:is(html[class~="dark"] .code-block pre) {
|
:is(html[class~="dark"] .code-block pre) {
|
||||||
border-color: hsl(var(--primary-hue) 100% 94% / 0.4);
|
border-color: hsl(var(--primary-hue) var(--primary-saturation) 94% / 0.4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.code-block .filename {
|
.code-block .filename {
|
||||||
@ -2185,7 +2202,7 @@ article details > summary::before {
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
border-top-left-radius: 0.75rem;
|
border-top-left-radius: 0.75rem;
|
||||||
border-top-right-radius: 0.75rem;
|
border-top-right-radius: 0.75rem;
|
||||||
background-color: hsl(var(--primary-hue) 100% 39% / 0.05);
|
background-color: hsl(var(--primary-hue) var(--primary-saturation) 39% / 0.05);
|
||||||
padding-top: 0.5rem;
|
padding-top: 0.5rem;
|
||||||
padding-bottom: 0.5rem;
|
padding-bottom: 0.5rem;
|
||||||
padding-left: 1rem;
|
padding-left: 1rem;
|
||||||
@ -2195,7 +2212,7 @@ article details > summary::before {
|
|||||||
color: rgb(55 65 81 / var(--tw-text-opacity));
|
color: rgb(55 65 81 / var(--tw-text-opacity));
|
||||||
}
|
}
|
||||||
:is(html[class~="dark"] .code-block .filename) {
|
:is(html[class~="dark"] .code-block .filename) {
|
||||||
background-color: hsl(var(--primary-hue) 100% 77% / 0.1);
|
background-color: hsl(var(--primary-hue) var(--primary-saturation) 77% / 0.1);
|
||||||
--tw-text-opacity: 1;
|
--tw-text-opacity: 1;
|
||||||
color: rgb(229 231 235 / var(--tw-text-opacity));
|
color: rgb(229 231 235 / var(--tw-text-opacity));
|
||||||
}
|
}
|
||||||
@ -2248,7 +2265,7 @@ article details > summary::before {
|
|||||||
.chroma .hl {
|
.chroma .hl {
|
||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background-color: hsl(var(--primary-hue) 100% 32% / 0.1);
|
background-color: hsl(var(--primary-hue) var(--primary-saturation) 32% / 0.1);
|
||||||
}
|
}
|
||||||
.hextra-cards {
|
.hextra-cards {
|
||||||
grid-template-columns: repeat(auto-fill, minmax(max(250px, calc((100% - 1rem * 2) / var(--rows))), 1fr));
|
grid-template-columns: repeat(auto-fill, minmax(max(250px, calc((100% - 1rem * 2) / var(--rows))), 1fr));
|
||||||
@ -2340,13 +2357,13 @@ article details > summary::before {
|
|||||||
}
|
}
|
||||||
.search-wrapper li .active {
|
.search-wrapper li .active {
|
||||||
border-radius: 0.375rem;
|
border-radius: 0.375rem;
|
||||||
background-color: hsl(var(--primary-hue) 100% 50% / 0.1);
|
background-color: hsl(var(--primary-hue) var(--primary-saturation) 50% / 0.1);
|
||||||
}
|
}
|
||||||
@media (prefers-contrast: more) {
|
@media (prefers-contrast: more) {
|
||||||
|
|
||||||
.search-wrapper li .active {
|
.search-wrapper li .active {
|
||||||
--tw-border-opacity: 1;
|
--tw-border-opacity: 1;
|
||||||
border-color: hsl(var(--primary-hue) 100% 50% / var(--tw-border-opacity));
|
border-color: hsl(var(--primary-hue) var(--primary-saturation) 50% / var(--tw-border-opacity));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.search-wrapper .no-result {
|
.search-wrapper .no-result {
|
||||||
@ -2433,7 +2450,7 @@ article details > summary::before {
|
|||||||
}
|
}
|
||||||
.search-wrapper .match {
|
.search-wrapper .match {
|
||||||
--tw-text-opacity: 1;
|
--tw-text-opacity: 1;
|
||||||
color: hsl(var(--primary-hue) 100% 45% / var(--tw-text-opacity));
|
color: hsl(var(--primary-hue) var(--primary-saturation) 45% / var(--tw-text-opacity));
|
||||||
}
|
}
|
||||||
@media (max-width: 767px) {
|
@media (max-width: 767px) {
|
||||||
.sidebar-container {
|
.sidebar-container {
|
||||||
@ -2572,11 +2589,13 @@ body {
|
|||||||
}
|
}
|
||||||
:root {
|
:root {
|
||||||
--primary-hue: 212deg;
|
--primary-hue: 212deg;
|
||||||
|
--primary-saturation: 100%;
|
||||||
--navbar-height: 4rem;
|
--navbar-height: 4rem;
|
||||||
--menu-height: 3.75rem;
|
--menu-height: 3.75rem;
|
||||||
}
|
}
|
||||||
.dark {
|
.dark {
|
||||||
--primary-hue: 204deg;
|
--primary-hue: 204deg;
|
||||||
|
--primary-saturation: 100%;
|
||||||
}
|
}
|
||||||
.placeholder\:text-gray-500::-moz-placeholder {
|
.placeholder\:text-gray-500::-moz-placeholder {
|
||||||
--tw-text-opacity: 1;
|
--tw-text-opacity: 1;
|
||||||
@ -2660,6 +2679,10 @@ body {
|
|||||||
--tw-border-opacity: 1;
|
--tw-border-opacity: 1;
|
||||||
border-color: rgb(156 163 175 / var(--tw-border-opacity));
|
border-color: rgb(156 163 175 / var(--tw-border-opacity));
|
||||||
}
|
}
|
||||||
|
.hover\:border-gray-900:hover {
|
||||||
|
--tw-border-opacity: 1;
|
||||||
|
border-color: rgb(17 24 39 / var(--tw-border-opacity));
|
||||||
|
}
|
||||||
.hover\:bg-gray-100:hover {
|
.hover\:bg-gray-100:hover {
|
||||||
--tw-bg-opacity: 1;
|
--tw-bg-opacity: 1;
|
||||||
background-color: rgb(243 244 246 / var(--tw-bg-opacity));
|
background-color: rgb(243 244 246 / var(--tw-bg-opacity));
|
||||||
@ -2669,11 +2692,11 @@ body {
|
|||||||
}
|
}
|
||||||
.hover\:bg-primary-50:hover {
|
.hover\:bg-primary-50:hover {
|
||||||
--tw-bg-opacity: 1;
|
--tw-bg-opacity: 1;
|
||||||
background-color: hsl(var(--primary-hue) 100% 97% / var(--tw-bg-opacity));
|
background-color: hsl(var(--primary-hue) var(--primary-saturation) 97% / var(--tw-bg-opacity));
|
||||||
}
|
}
|
||||||
.hover\:bg-primary-700:hover {
|
.hover\:bg-primary-700:hover {
|
||||||
--tw-bg-opacity: 1;
|
--tw-bg-opacity: 1;
|
||||||
background-color: hsl(var(--primary-hue) 100% 39% / var(--tw-bg-opacity));
|
background-color: hsl(var(--primary-hue) var(--primary-saturation) 39% / var(--tw-bg-opacity));
|
||||||
}
|
}
|
||||||
.hover\:bg-slate-50:hover {
|
.hover\:bg-slate-50:hover {
|
||||||
--tw-bg-opacity: 1;
|
--tw-bg-opacity: 1;
|
||||||
@ -2693,7 +2716,7 @@ body {
|
|||||||
}
|
}
|
||||||
.hover\:text-primary-600:hover {
|
.hover\:text-primary-600:hover {
|
||||||
--tw-text-opacity: 1;
|
--tw-text-opacity: 1;
|
||||||
color: hsl(var(--primary-hue) 100% 45% / var(--tw-text-opacity));
|
color: hsl(var(--primary-hue) var(--primary-saturation) 45% / var(--tw-text-opacity));
|
||||||
}
|
}
|
||||||
.hover\:opacity-60:hover {
|
.hover\:opacity-60:hover {
|
||||||
opacity: 0.6;
|
opacity: 0.6;
|
||||||
@ -2730,7 +2753,7 @@ body {
|
|||||||
}
|
}
|
||||||
.focus\:ring-primary-300:focus {
|
.focus\:ring-primary-300:focus {
|
||||||
--tw-ring-opacity: 1;
|
--tw-ring-opacity: 1;
|
||||||
--tw-ring-color: hsl(var(--primary-hue) 100% 77% / var(--tw-ring-opacity));
|
--tw-ring-color: hsl(var(--primary-hue) var(--primary-saturation) 77% / var(--tw-ring-opacity));
|
||||||
}
|
}
|
||||||
.active\:bg-gray-400\/20:active {
|
.active\:bg-gray-400\/20:active {
|
||||||
background-color: rgb(156 163 175 / 0.2);
|
background-color: rgb(156 163 175 / 0.2);
|
||||||
@ -2772,11 +2795,11 @@ body {
|
|||||||
}
|
}
|
||||||
.data-\[state\=selected\]\:border-primary-500[data-state=selected] {
|
.data-\[state\=selected\]\:border-primary-500[data-state=selected] {
|
||||||
--tw-border-opacity: 1;
|
--tw-border-opacity: 1;
|
||||||
border-color: hsl(var(--primary-hue) 100% 50% / var(--tw-border-opacity));
|
border-color: hsl(var(--primary-hue) var(--primary-saturation) 50% / var(--tw-border-opacity));
|
||||||
}
|
}
|
||||||
.data-\[state\=selected\]\:text-primary-600[data-state=selected] {
|
.data-\[state\=selected\]\:text-primary-600[data-state=selected] {
|
||||||
--tw-text-opacity: 1;
|
--tw-text-opacity: 1;
|
||||||
color: hsl(var(--primary-hue) 100% 45% / var(--tw-text-opacity));
|
color: hsl(var(--primary-hue) var(--primary-saturation) 45% / var(--tw-text-opacity));
|
||||||
}
|
}
|
||||||
.group[data-theme=dark] .group-data-\[theme\=dark\]\:hidden {
|
.group[data-theme=dark] .group-data-\[theme\=dark\]\:hidden {
|
||||||
display: none;
|
display: none;
|
||||||
@ -2918,6 +2941,11 @@ body {
|
|||||||
border-color: currentColor;
|
border-color: currentColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.contrast-more\:border-gray-800 {
|
||||||
|
--tw-border-opacity: 1;
|
||||||
|
border-color: rgb(31 41 55 / var(--tw-border-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
.contrast-more\:border-gray-900 {
|
.contrast-more\:border-gray-900 {
|
||||||
--tw-border-opacity: 1;
|
--tw-border-opacity: 1;
|
||||||
border-color: rgb(17 24 39 / var(--tw-border-opacity));
|
border-color: rgb(17 24 39 / var(--tw-border-opacity));
|
||||||
@ -2930,7 +2958,7 @@ body {
|
|||||||
|
|
||||||
.contrast-more\:border-primary-500 {
|
.contrast-more\:border-primary-500 {
|
||||||
--tw-border-opacity: 1;
|
--tw-border-opacity: 1;
|
||||||
border-color: hsl(var(--primary-hue) 100% 50% / var(--tw-border-opacity));
|
border-color: hsl(var(--primary-hue) var(--primary-saturation) 50% / var(--tw-border-opacity));
|
||||||
}
|
}
|
||||||
|
|
||||||
.contrast-more\:border-transparent {
|
.contrast-more\:border-transparent {
|
||||||
@ -2993,6 +3021,10 @@ body {
|
|||||||
:is(html[class~="dark"] .dark\:border-gray-100\/20) {
|
:is(html[class~="dark"] .dark\:border-gray-100\/20) {
|
||||||
border-color: rgb(243 244 246 / 0.2);
|
border-color: rgb(243 244 246 / 0.2);
|
||||||
}
|
}
|
||||||
|
:is(html[class~="dark"] .dark\:border-gray-400) {
|
||||||
|
--tw-border-opacity: 1;
|
||||||
|
border-color: rgb(156 163 175 / var(--tw-border-opacity));
|
||||||
|
}
|
||||||
:is(html[class~="dark"] .dark\:border-neutral-700) {
|
:is(html[class~="dark"] .dark\:border-neutral-700) {
|
||||||
--tw-border-opacity: 1;
|
--tw-border-opacity: 1;
|
||||||
border-color: rgb(64 64 64 / var(--tw-border-opacity));
|
border-color: rgb(64 64 64 / var(--tw-border-opacity));
|
||||||
@ -3038,14 +3070,14 @@ body {
|
|||||||
background-color: rgb(251 146 60 / 0.2);
|
background-color: rgb(251 146 60 / 0.2);
|
||||||
}
|
}
|
||||||
:is(html[class~="dark"] .dark\:bg-primary-300\/10) {
|
:is(html[class~="dark"] .dark\:bg-primary-300\/10) {
|
||||||
background-color: hsl(var(--primary-hue) 100% 77% / 0.1);
|
background-color: hsl(var(--primary-hue) var(--primary-saturation) 77% / 0.1);
|
||||||
}
|
}
|
||||||
:is(html[class~="dark"] .dark\:bg-primary-400\/10) {
|
:is(html[class~="dark"] .dark\:bg-primary-400\/10) {
|
||||||
background-color: hsl(var(--primary-hue) 100% 66% / 0.1);
|
background-color: hsl(var(--primary-hue) var(--primary-saturation) 66% / 0.1);
|
||||||
}
|
}
|
||||||
:is(html[class~="dark"] .dark\:bg-primary-600) {
|
:is(html[class~="dark"] .dark\:bg-primary-600) {
|
||||||
--tw-bg-opacity: 1;
|
--tw-bg-opacity: 1;
|
||||||
background-color: hsl(var(--primary-hue) 100% 45% / var(--tw-bg-opacity));
|
background-color: hsl(var(--primary-hue) var(--primary-saturation) 45% / var(--tw-bg-opacity));
|
||||||
}
|
}
|
||||||
:is(html[class~="dark"] .dark\:bg-red-900\/30) {
|
:is(html[class~="dark"] .dark\:bg-red-900\/30) {
|
||||||
background-color: rgb(127 29 29 / 0.3);
|
background-color: rgb(127 29 29 / 0.3);
|
||||||
@ -3099,7 +3131,7 @@ body {
|
|||||||
}
|
}
|
||||||
:is(html[class~="dark"] .dark\:text-primary-600) {
|
:is(html[class~="dark"] .dark\:text-primary-600) {
|
||||||
--tw-text-opacity: 1;
|
--tw-text-opacity: 1;
|
||||||
color: hsl(var(--primary-hue) 100% 45% / var(--tw-text-opacity));
|
color: hsl(var(--primary-hue) var(--primary-saturation) 45% / var(--tw-text-opacity));
|
||||||
}
|
}
|
||||||
:is(html[class~="dark"] .dark\:text-red-200) {
|
:is(html[class~="dark"] .dark\:text-red-200) {
|
||||||
--tw-text-opacity: 1;
|
--tw-text-opacity: 1;
|
||||||
@ -3152,6 +3184,10 @@ body {
|
|||||||
--tw-invert: invert(100%);
|
--tw-invert: invert(100%);
|
||||||
filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
|
filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
|
||||||
}
|
}
|
||||||
|
:is(html[class~="dark"] .dark\:hover\:border-gray-100:hover) {
|
||||||
|
--tw-border-opacity: 1;
|
||||||
|
border-color: rgb(243 244 246 / var(--tw-border-opacity));
|
||||||
|
}
|
||||||
:is(html[class~="dark"] .dark\:hover\:border-gray-600:hover) {
|
:is(html[class~="dark"] .dark\:hover\:border-gray-600:hover) {
|
||||||
--tw-border-opacity: 1;
|
--tw-border-opacity: 1;
|
||||||
border-color: rgb(75 85 99 / var(--tw-border-opacity));
|
border-color: rgb(75 85 99 / var(--tw-border-opacity));
|
||||||
@ -3184,14 +3220,14 @@ body {
|
|||||||
background-color: rgb(23 23 23 / var(--tw-bg-opacity));
|
background-color: rgb(23 23 23 / var(--tw-bg-opacity));
|
||||||
}
|
}
|
||||||
:is(html[class~="dark"] .dark\:hover\:bg-primary-100\/5:hover) {
|
:is(html[class~="dark"] .dark\:hover\:bg-primary-100\/5:hover) {
|
||||||
background-color: hsl(var(--primary-hue) 100% 94% / 0.05);
|
background-color: hsl(var(--primary-hue) var(--primary-saturation) 94% / 0.05);
|
||||||
}
|
}
|
||||||
:is(html[class~="dark"] .dark\:hover\:bg-primary-700:hover) {
|
:is(html[class~="dark"] .dark\:hover\:bg-primary-700:hover) {
|
||||||
--tw-bg-opacity: 1;
|
--tw-bg-opacity: 1;
|
||||||
background-color: hsl(var(--primary-hue) 100% 39% / var(--tw-bg-opacity));
|
background-color: hsl(var(--primary-hue) var(--primary-saturation) 39% / var(--tw-bg-opacity));
|
||||||
}
|
}
|
||||||
:is(html[class~="dark"] .hover\:dark\:bg-primary-500\/10):hover {
|
:is(html[class~="dark"] .hover\:dark\:bg-primary-500\/10):hover {
|
||||||
background-color: hsl(var(--primary-hue) 100% 50% / 0.1);
|
background-color: hsl(var(--primary-hue) var(--primary-saturation) 50% / 0.1);
|
||||||
}
|
}
|
||||||
:is(html[class~="dark"] .dark\:hover\:text-gray-100:hover) {
|
:is(html[class~="dark"] .dark\:hover\:text-gray-100:hover) {
|
||||||
--tw-text-opacity: 1;
|
--tw-text-opacity: 1;
|
||||||
@ -3219,7 +3255,7 @@ body {
|
|||||||
}
|
}
|
||||||
:is(html[class~="dark"] .hover\:dark\:text-primary-600):hover {
|
:is(html[class~="dark"] .hover\:dark\:text-primary-600):hover {
|
||||||
--tw-text-opacity: 1;
|
--tw-text-opacity: 1;
|
||||||
color: hsl(var(--primary-hue) 100% 45% / var(--tw-text-opacity));
|
color: hsl(var(--primary-hue) var(--primary-saturation) 45% / var(--tw-text-opacity));
|
||||||
}
|
}
|
||||||
:is(html[class~="dark"] .dark\:hover\:shadow-none:hover) {
|
:is(html[class~="dark"] .dark\:hover\:shadow-none:hover) {
|
||||||
--tw-shadow: 0 0 #0000;
|
--tw-shadow: 0 0 #0000;
|
||||||
@ -3232,7 +3268,7 @@ body {
|
|||||||
}
|
}
|
||||||
:is(html[class~="dark"] .dark\:focus\:ring-primary-800:focus) {
|
:is(html[class~="dark"] .dark\:focus\:ring-primary-800:focus) {
|
||||||
--tw-ring-opacity: 1;
|
--tw-ring-opacity: 1;
|
||||||
--tw-ring-color: hsl(var(--primary-hue) 100% 32% / var(--tw-ring-opacity));
|
--tw-ring-color: hsl(var(--primary-hue) var(--primary-saturation) 32% / var(--tw-ring-opacity));
|
||||||
}
|
}
|
||||||
@media (prefers-contrast: more) {
|
@media (prefers-contrast: more) {
|
||||||
|
|
||||||
@ -3252,7 +3288,7 @@ body {
|
|||||||
|
|
||||||
:is(html[class~="dark"] .contrast-more\:dark\:border-primary-500) {
|
:is(html[class~="dark"] .contrast-more\:dark\:border-primary-500) {
|
||||||
--tw-border-opacity: 1;
|
--tw-border-opacity: 1;
|
||||||
border-color: hsl(var(--primary-hue) 100% 50% / var(--tw-border-opacity));
|
border-color: hsl(var(--primary-hue) var(--primary-saturation) 50% / var(--tw-border-opacity));
|
||||||
}
|
}
|
||||||
|
|
||||||
:is(html[class~="dark"] .dark\:contrast-more\:border-neutral-400) {
|
:is(html[class~="dark"] .dark\:contrast-more\:border-neutral-400) {
|
||||||
|
@ -21,10 +21,12 @@ body {
|
|||||||
|
|
||||||
:root {
|
:root {
|
||||||
--primary-hue: 212deg;
|
--primary-hue: 212deg;
|
||||||
|
--primary-saturation: 100%;
|
||||||
--navbar-height: 4rem;
|
--navbar-height: 4rem;
|
||||||
--menu-height: 3.75rem;
|
--menu-height: 3.75rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dark {
|
.dark {
|
||||||
--primary-hue: 204deg;
|
--primary-hue: 204deg;
|
||||||
|
--primary-saturation: 100%;
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,9 @@
|
|||||||
p {
|
p {
|
||||||
@apply mt-6 leading-7 first:mt-0;
|
@apply mt-6 leading-7 first:mt-0;
|
||||||
}
|
}
|
||||||
|
.not-prose p {
|
||||||
|
@apply mt-0 leading-normal;
|
||||||
|
}
|
||||||
a {
|
a {
|
||||||
@apply text-primary-600 underline decoration-from-font [text-underline-position:from-font];
|
@apply text-primary-600 underline decoration-from-font [text-underline-position:from-font];
|
||||||
}
|
}
|
||||||
|
22
assets/js/back-to-top.js
Normal file
22
assets/js/back-to-top.js
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
// Back to top button
|
||||||
|
|
||||||
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
|
const backToTop = document.querySelector("#backToTop");
|
||||||
|
if (backToTop) {
|
||||||
|
document.addEventListener("scroll", (e) => {
|
||||||
|
if (window.scrollY > 300) {
|
||||||
|
backToTop.classList.remove("opacity-0");
|
||||||
|
} else {
|
||||||
|
backToTop.classList.add("opacity-0");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function scrollUp() {
|
||||||
|
window.scroll({
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
behavior: "smooth",
|
||||||
|
});
|
||||||
|
}
|
@ -1,30 +1,63 @@
|
|||||||
document.querySelectorAll('.code-copy-btn').forEach(function (button) {
|
// Copy button for code blocks
|
||||||
button.addEventListener('click', function (e) {
|
|
||||||
e.preventDefault();
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
const targetId = button.getAttribute('data-clipboard-target');
|
const getCopyIcon = () => {
|
||||||
const target = document.querySelector(targetId);
|
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
||||||
let codeElement;
|
svg.innerHTML = `
|
||||||
if (target.tagName === 'CODE') {
|
<path stroke-linecap="round" stroke-linejoin="round" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" />
|
||||||
codeElement = target;
|
`;
|
||||||
} else {
|
svg.setAttribute('fill', 'none');
|
||||||
// Select the last code element in case line numbers are present
|
svg.setAttribute('viewBox', '0 0 24 24');
|
||||||
const codeElements = target.querySelectorAll('code');
|
svg.setAttribute('stroke', 'currentColor');
|
||||||
codeElement = codeElements[codeElements.length - 1];
|
svg.setAttribute('stroke-width', '2');
|
||||||
}
|
return svg;
|
||||||
if (codeElement) {
|
}
|
||||||
// Replace double newlines with single newlines in the innerText
|
|
||||||
// as each line inside <span> has trailing newline '\n'
|
const getSuccessIcon = () => {
|
||||||
const code = codeElement.innerText.replace(/\n\n/g, '\n');
|
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
||||||
navigator.clipboard.writeText(code).then(function () {
|
svg.innerHTML = `
|
||||||
button.classList.add('copied');
|
<path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7" />
|
||||||
setTimeout(function () {
|
`;
|
||||||
button.classList.remove('copied');
|
svg.setAttribute('fill', 'none');
|
||||||
}, 500);
|
svg.setAttribute('viewBox', '0 0 24 24');
|
||||||
}).catch(function (err) {
|
svg.setAttribute('stroke', 'currentColor');
|
||||||
console.error('Failed to copy text: ', err);
|
svg.setAttribute('stroke-width', '2');
|
||||||
});
|
return svg;
|
||||||
} else {
|
}
|
||||||
console.error('Target element not found');
|
|
||||||
}
|
document.querySelectorAll('.code-copy-btn').forEach(function (button) {
|
||||||
|
// Add copy and success icons
|
||||||
|
button.querySelector('.copy-icon')?.appendChild(getCopyIcon());
|
||||||
|
button.querySelector('.success-icon')?.appendChild(getSuccessIcon());
|
||||||
|
|
||||||
|
// Add click event listener for copy button
|
||||||
|
button.addEventListener('click', function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
const targetId = button.getAttribute('data-clipboard-target');
|
||||||
|
const target = document.querySelector(targetId);
|
||||||
|
let codeElement;
|
||||||
|
if (target.tagName === 'CODE') {
|
||||||
|
codeElement = target;
|
||||||
|
} else {
|
||||||
|
// Select the last code element in case line numbers are present
|
||||||
|
const codeElements = target.querySelectorAll('code');
|
||||||
|
codeElement = codeElements[codeElements.length - 1];
|
||||||
|
}
|
||||||
|
if (codeElement) {
|
||||||
|
// Replace double newlines with single newlines in the innerText
|
||||||
|
// as each line inside <span> has trailing newline '\n'
|
||||||
|
const code = codeElement.innerText.replace(/\n\n/g, '\n');
|
||||||
|
navigator.clipboard.writeText(code).then(function () {
|
||||||
|
button.classList.add('copied');
|
||||||
|
setTimeout(function () {
|
||||||
|
button.classList.remove('copied');
|
||||||
|
}, 500);
|
||||||
|
}).catch(function (err) {
|
||||||
|
console.error('Failed to copy text: ', err);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.error('Target element not found');
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,5 +1,16 @@
|
|||||||
// Search functionality using FlexSearch.
|
// Search functionality using FlexSearch.
|
||||||
|
|
||||||
|
// Change shortcut key to cmd+k on Mac, iPad or iPhone.
|
||||||
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
|
if (/iPad|iPhone|Macintosh/.test(navigator.userAgent)) {
|
||||||
|
// select the kbd element under the .search-wrapper class
|
||||||
|
const keys = document.querySelectorAll(".search-wrapper kbd");
|
||||||
|
keys.forEach(key => {
|
||||||
|
key.innerHTML = '<span class="text-xs">⌘</span>K';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Render the search data as JSON.
|
// Render the search data as JSON.
|
||||||
// {{ $searchDataFile := printf "%s.search-data.json" .Language.Lang }}
|
// {{ $searchDataFile := printf "%s.search-data.json" .Language.Lang }}
|
||||||
// {{ $searchData := resources.Get "json/search-data.json" | resources.ExecuteAsTemplate $searchDataFile . }}
|
// {{ $searchData := resources.Get "json/search-data.json" | resources.ExecuteAsTemplate $searchDataFile . }}
|
||||||
|
@ -1,40 +1,51 @@
|
|||||||
// Dark theme toggle
|
// Light / Dark theme toggle
|
||||||
|
(function () {
|
||||||
|
const defaultTheme = '{{ site.Params.theme.default | default `system`}}'
|
||||||
|
|
||||||
const themeToggleButtons = document.querySelectorAll(".theme-toggle");
|
const themeToggleButtons = document.querySelectorAll(".theme-toggle");
|
||||||
|
|
||||||
// Change the icons inside the button based on previous settings
|
// Change the icons of the buttons based on previous settings or system theme
|
||||||
if (
|
if (
|
||||||
localStorage.getItem("color-theme") === "dark" ||
|
localStorage.getItem("color-theme") === "dark" ||
|
||||||
(!("color-theme" in localStorage) && window.matchMedia("(prefers-color-scheme: dark)").matches)
|
(!("color-theme" in localStorage) &&
|
||||||
) {
|
((window.matchMedia("(prefers-color-scheme: dark)").matches && defaultTheme === "system") || defaultTheme === "dark"))
|
||||||
themeToggleButtons.forEach((el) => el.dataset.theme = "dark");
|
) {
|
||||||
} else {
|
themeToggleButtons.forEach((el) => el.dataset.theme = "dark");
|
||||||
themeToggleButtons.forEach((el) => el.dataset.theme = "light");
|
} else {
|
||||||
}
|
themeToggleButtons.forEach((el) => el.dataset.theme = "light");
|
||||||
|
}
|
||||||
|
|
||||||
themeToggleButtons.forEach((el) => {
|
// Add click event handler to the buttons
|
||||||
el.addEventListener("click", function () {
|
themeToggleButtons.forEach((el) => {
|
||||||
if (localStorage.getItem("color-theme")) {
|
el.addEventListener("click", function () {
|
||||||
if (localStorage.getItem("color-theme") === "light") {
|
if (localStorage.getItem("color-theme")) {
|
||||||
document.documentElement.classList.add("dark");
|
if (localStorage.getItem("color-theme") === "light") {
|
||||||
document.documentElement.style.colorScheme = "dark";
|
setDarkTheme();
|
||||||
localStorage.setItem("color-theme", "dark");
|
localStorage.setItem("color-theme", "dark");
|
||||||
|
} else {
|
||||||
|
setLightTheme();
|
||||||
|
localStorage.setItem("color-theme", "light");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
document.documentElement.classList.remove("dark");
|
if (document.documentElement.classList.contains("dark")) {
|
||||||
document.documentElement.style.colorScheme = "light";
|
setLightTheme();
|
||||||
localStorage.setItem("color-theme", "light");
|
localStorage.setItem("color-theme", "light");
|
||||||
|
} else {
|
||||||
|
setDarkTheme();
|
||||||
|
localStorage.setItem("color-theme", "dark");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
el.dataset.theme = document.documentElement.classList.contains("dark") ? "dark" : "light";
|
||||||
if (document.documentElement.classList.contains("dark")) {
|
});
|
||||||
document.documentElement.classList.remove("dark");
|
|
||||||
document.documentElement.style.colorScheme = "light";
|
|
||||||
localStorage.setItem("color-theme", "light");
|
|
||||||
} else {
|
|
||||||
document.documentElement.classList.add("dark");
|
|
||||||
document.documentElement.style.colorScheme = "dark";
|
|
||||||
localStorage.setItem("color-theme", "dark");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
el.dataset.theme = document.documentElement.classList.contains("dark") ? "dark" : "light";
|
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
// Listen for system theme changes
|
||||||
|
window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", (e) => {
|
||||||
|
if (defaultTheme === "system" && !("color-theme" in localStorage)) {
|
||||||
|
e.matches ? setDarkTheme() : setLightTheme();
|
||||||
|
themeToggleButtons.forEach((el) =>
|
||||||
|
el.dataset.theme = document.documentElement.classList.contains("dark") ? "dark" : "light"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
@ -1,3 +1,10 @@
|
|||||||
|
{{/* FlexSearch Index Data */}}
|
||||||
|
{{- $indexType := site.Params.search.flexsearch.index | default "content" -}}
|
||||||
|
|
||||||
|
{{- if not (in (slice "content" "summary" "heading" "title" ) $indexType) -}}
|
||||||
|
{{- errorf "unknown flexsearch index type: %s" $indexType -}}
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
{{- $pages := where .Site.Pages "Kind" "in" (slice "page" "section") -}}
|
{{- $pages := where .Site.Pages "Kind" "in" (slice "page" "section") -}}
|
||||||
{{- $pages = where $pages "Params.excludeSearch" "!=" true -}}
|
{{- $pages = where $pages "Params.excludeSearch" "!=" true -}}
|
||||||
{{- $pages = where $pages "Content" "!=" "" -}}
|
{{- $pages = where $pages "Content" "!=" "" -}}
|
||||||
@ -7,7 +14,7 @@
|
|||||||
{{- range $index, $page := $pages -}}
|
{{- range $index, $page := $pages -}}
|
||||||
{{- $pageTitle := $page.LinkTitle | default $page.File.BaseFileName -}}
|
{{- $pageTitle := $page.LinkTitle | default $page.File.BaseFileName -}}
|
||||||
{{- $pageLink := $page.RelPermalink -}}
|
{{- $pageLink := $page.RelPermalink -}}
|
||||||
{{- $data := partial "utils/fragments" $page -}}
|
{{- $data := partial "utils/fragments" (dict "context" $page "type" $indexType) -}}
|
||||||
{{- $output = $output | merge (dict $pageLink (dict "title" $pageTitle "data" $data)) -}}
|
{{- $output = $output | merge (dict $pageLink (dict "title" $pageTitle "data" $data)) -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
|
@ -12,4 +12,5 @@ This section covers some advanced topics of the theme.
|
|||||||
{{< cards >}}
|
{{< cards >}}
|
||||||
{{< card link="multi-language" title="Multi-language" icon="translate" >}}
|
{{< card link="multi-language" title="Multi-language" icon="translate" >}}
|
||||||
{{< card link="customization" title="Customization" icon="pencil" >}}
|
{{< card link="customization" title="Customization" icon="pencil" >}}
|
||||||
|
{{< card link="comments" title="Comments System" icon="chat-alt" >}}
|
||||||
{{< /cards >}}
|
{{< /cards >}}
|
||||||
|
39
exampleSite/content/docs/advanced/comments.md
Normal file
39
exampleSite/content/docs/advanced/comments.md
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
---
|
||||||
|
title: Comments System
|
||||||
|
linkTitle: Comments
|
||||||
|
---
|
||||||
|
|
||||||
|
Hextra supports adding comments system to your site.
|
||||||
|
Currently [giscus](https://giscus.app/) is supported.
|
||||||
|
|
||||||
|
<!--more-->
|
||||||
|
|
||||||
|
## giscus
|
||||||
|
|
||||||
|
[giscus](https://giscus.app/) is a comments system powered by [GitHub Discussions](https://docs.github.com/en/discussions). It is free and open source.
|
||||||
|
|
||||||
|
To enable giscus, you need to add the following to the site configuration file:
|
||||||
|
|
||||||
|
```yaml {filename="hugo.yaml"}
|
||||||
|
params:
|
||||||
|
comments:
|
||||||
|
enable: false
|
||||||
|
type: giscus
|
||||||
|
|
||||||
|
giscus:
|
||||||
|
repo: <repository>
|
||||||
|
repoId: <repository ID>
|
||||||
|
category: <category>
|
||||||
|
categoryId: <category ID>
|
||||||
|
```
|
||||||
|
|
||||||
|
The giscus configurations can be constructed from the [giscus.app](https://giscus.app/) website. More details can also be found there.
|
||||||
|
|
||||||
|
Comments can be enabled or disabled for a specific page in the page front matter:
|
||||||
|
|
||||||
|
```yaml {filename="content/docs/about.md"}
|
||||||
|
---
|
||||||
|
title: About
|
||||||
|
comments: true
|
||||||
|
---
|
||||||
|
```
|
@ -34,11 +34,12 @@ The color of text mixed with `other text` can customized with:
|
|||||||
|
|
||||||
### Primary Color
|
### Primary Color
|
||||||
|
|
||||||
The primary color of the theme can be customized by setting the `--primary-hue` variable:
|
The primary color of the theme can be customized by setting the `--primary-hue` and `--primary-saturation` variables:
|
||||||
|
|
||||||
```css {filename="assets/css/custom.css"}
|
```css {filename="assets/css/custom.css"}
|
||||||
:root {
|
:root {
|
||||||
--primary-hue: 100deg;
|
--primary-hue: 100deg;
|
||||||
|
--primary-saturation: 90%;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -19,18 +19,29 @@ We have provided a [GitHub Actions workflow](https://docs.github.com/en/pages/ge
|
|||||||
|
|
||||||
## Start as New Project
|
## Start as New Project
|
||||||
|
|
||||||
### Prerequisites
|
There are two main ways to add the Hextra theme to your Hugo project.
|
||||||
|
|
||||||
Before we start, make sure we have [Hugo](https://gohugo.io/) installed.
|
1. **Hugo Modules (Recommended)**: The simplest and recommended method. [Hugo modules](https://gohugo.io/hugo-modules/) let you pull in the theme directly from its online source. Theme is downloaded automatically and managed by Hugo.
|
||||||
Please refer to Hugo's [official installation guide](https://gohugo.io/installation/) for more details.
|
|
||||||
|
|
||||||
[Hugo modules](https://gohugo.io/hugo-modules/) are the recommended way to manage Hugo themes. To use Hugo modules, we need to install [Git](https://git-scm.com/) and [Go](https://go.dev/).
|
2. **Git Submodule**: Alternatively, add Hextra as a [Git Submodule](https://git-scm.com/book/en/v2/Git-Tools-Submodules). The theme will be downloaded by Git and stored in your project's `themes` folder.
|
||||||
|
|
||||||
|
### Setup Hextra as Hugo module
|
||||||
|
|
||||||
|
#### Prerequisites
|
||||||
|
|
||||||
|
Before starting, you need to have the following softwares installed:
|
||||||
|
|
||||||
|
- [Hugo (extended version)](https://gohugo.io/installation/)
|
||||||
|
- [Git](https://git-scm.com/)
|
||||||
|
- [Go](https://go.dev/)
|
||||||
|
|
||||||
|
#### Steps
|
||||||
|
|
||||||
{{% steps %}}
|
{{% steps %}}
|
||||||
|
|
||||||
### Initialize a new Hugo site
|
### Initialize a new Hugo site
|
||||||
|
|
||||||
```bash
|
```shell
|
||||||
$ hugo new site my-site --format=yaml
|
$ hugo new site my-site --format=yaml
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -45,7 +56,7 @@ $ hugo mod init github.com/username/my-site
|
|||||||
$ hugo mod get github.com/imfing/hextra
|
$ hugo mod get github.com/imfing/hextra
|
||||||
```
|
```
|
||||||
|
|
||||||
Edit `hugo.yaml` to enable Hextra theme:
|
Configure `hugo.yaml` to use Hextra theme by adding the following:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
module:
|
module:
|
||||||
@ -55,7 +66,7 @@ module:
|
|||||||
|
|
||||||
### Create your first content pages
|
### Create your first content pages
|
||||||
|
|
||||||
Let's create a new content page for the home page and the documentation page:
|
Let's create new content page for the home page and the documentation page:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ hugo new content/_index.md
|
$ hugo new content/_index.md
|
||||||
@ -73,20 +84,101 @@ Voila! You can see your new site at `http://localhost:1313/`.
|
|||||||
{{% /steps %}}
|
{{% /steps %}}
|
||||||
|
|
||||||
|
|
||||||
## Update Theme
|
|
||||||
|
|
||||||
{{% details title="How to update theme?" %}}
|
{{% details title="How to update theme?" %}}
|
||||||
|
|
||||||
To update the theme to the [latest released version](https://github.com/imfing/hextra/releases), run the following command:
|
To update all Hugo modules in your project to their latest versions, run the following command:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ hugo mod get -u
|
$ hugo mod get -u
|
||||||
```
|
```
|
||||||
|
|
||||||
|
To update only Hextra to the [latest released version](https://github.com/imfing/hextra/releases), run the following command:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
hugo mod get -u github.com/imfing/hextra
|
||||||
|
```
|
||||||
|
|
||||||
See [Hugo Modules](https://gohugo.io/hugo-modules/use-modules/#update-all-modules) for more details.
|
See [Hugo Modules](https://gohugo.io/hugo-modules/use-modules/#update-all-modules) for more details.
|
||||||
|
|
||||||
{{% /details %}}
|
{{% /details %}}
|
||||||
|
|
||||||
|
### Setup Hextra as Git submodule
|
||||||
|
|
||||||
|
#### Prerequisites
|
||||||
|
|
||||||
|
Before starting, you need to have the following softwares installed:
|
||||||
|
|
||||||
|
- [Hugo (extended version)](https://gohugo.io/installation/)
|
||||||
|
- [Git](https://git-scm.com/)
|
||||||
|
|
||||||
|
#### Steps
|
||||||
|
|
||||||
|
{{% steps %}}
|
||||||
|
|
||||||
|
### Initialize a new Hugo site
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ hugo new site my-site --format=yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
### Add Hextra theme as a Git submodule
|
||||||
|
|
||||||
|
```shell
|
||||||
|
git submodule add https://github.com/imfing/hextra.git themes/hextra
|
||||||
|
```
|
||||||
|
|
||||||
|
Configure `hugo.yaml` to use Hextra theme by adding the following:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
theme: hextra
|
||||||
|
```
|
||||||
|
|
||||||
|
### Create your first content pages
|
||||||
|
|
||||||
|
Let's create new content page for the home page and the documentation page:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ hugo new content/_index.md
|
||||||
|
$ hugo new content/docs/_index.md
|
||||||
|
```
|
||||||
|
|
||||||
|
### Preview the site locally
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ hugo server --buildDrafts --disableFastRender
|
||||||
|
```
|
||||||
|
|
||||||
|
Voila! You can see your new site at `http://localhost:1313/`.
|
||||||
|
|
||||||
|
{{% /steps %}}
|
||||||
|
|
||||||
|
|
||||||
|
When using [CI/CD](https://en.wikipedia.org/wiki/CI/CD) for Hugo website deployment, it's essential to ensure that the following command is executed before running the `hugo` command.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
git submodule update --init
|
||||||
|
```
|
||||||
|
|
||||||
|
Failure to run this command will result in the theme folder not being populated with Hextra theme files, leading to a build failure.
|
||||||
|
|
||||||
|
|
||||||
|
{{% details title="How to update theme?" %}}
|
||||||
|
|
||||||
|
To update all submodules in your repository to their latest commits, run the following command:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ git submodule update --remote
|
||||||
|
```
|
||||||
|
|
||||||
|
To update only Hextra to the latest commit, run the following command:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
git submodule update --remote themes/hextra
|
||||||
|
```
|
||||||
|
|
||||||
|
See [Git submodules](https://git-scm.com/book/en/v2/Git-Tools-Submodules) for more details.
|
||||||
|
|
||||||
|
{{% /details %}}
|
||||||
|
|
||||||
## Next
|
## Next
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ weight: 2
|
|||||||
|
|
||||||
Hugo reads its configuration from `hugo.yaml` in the root of your Hugo site.
|
Hugo reads its configuration from `hugo.yaml` in the root of your Hugo site.
|
||||||
The config file is where you can configure all aspects of your site.
|
The config file is where you can configure all aspects of your site.
|
||||||
You can find the config file for this site in `exampleSite/hugo.yaml` as a good starting point.
|
Check out the config file for this site [`exampleSite/hugo.yaml`](https://github.com/imfing/hextra/blob/main/exampleSite/hugo.yaml) on GitHub to get a comprehensive idea of available settings and best practices.
|
||||||
|
|
||||||
<!--more-->
|
<!--more-->
|
||||||
|
|
||||||
@ -181,6 +181,26 @@ Include both `favicon.ico` and `favicon.svg` files in your project to ensure you
|
|||||||
While `favicon.ico` is generally for older browsers, `favicon.svg` is supported by modern ones. The optional `favicon-dark.svg` can be included for a tailored experience in dark mode.
|
While `favicon.ico` is generally for older browsers, `favicon.svg` is supported by modern ones. The optional `favicon-dark.svg` can be included for a tailored experience in dark mode.
|
||||||
Feel free to use tools like [favicon.io](https://favicon.io/) or [favycon](https://github.com/ruisaraiva19/favycon) to generate these icons.
|
Feel free to use tools like [favicon.io](https://favicon.io/) or [favycon](https://github.com/ruisaraiva19/favycon) to generate these icons.
|
||||||
|
|
||||||
|
### Theme Configuration
|
||||||
|
|
||||||
|
Use the `theme` setting to configure the default theme mode and toggle button, allowing visitors to switch between light or dark mode.
|
||||||
|
|
||||||
|
```yaml {filename="hugo.yaml"}
|
||||||
|
params:
|
||||||
|
theme:
|
||||||
|
# light | dark | system
|
||||||
|
default: system
|
||||||
|
displayToggle: true
|
||||||
|
```
|
||||||
|
|
||||||
|
Options for `theme.default`:
|
||||||
|
|
||||||
|
- `light` - always use light mode
|
||||||
|
- `dark` - always use dark mode
|
||||||
|
- `system` - sync with the operating system setting (default)
|
||||||
|
|
||||||
|
The `theme.displayToggle` parameter allows you to display a toggle button for changing themes.
|
||||||
|
When set to `true`, visitors can switch between light or dark mode, overriding the default setting.
|
||||||
|
|
||||||
### Page Width
|
### Page Width
|
||||||
|
|
||||||
@ -193,11 +213,42 @@ params:
|
|||||||
width: wide
|
width: wide
|
||||||
```
|
```
|
||||||
|
|
||||||
There are three available options: `full`, `wide`, and `normal`.
|
There are three available options: `full`, `wide`, and `normal`. By default, the page width is set to `normal`.
|
||||||
By default, the page width is set to `normal`.
|
|
||||||
|
|
||||||
Similarly, the width of the navbar and footer can be customized by the `params.navbar.width` and `params.footer.width` parameters.
|
Similarly, the width of the navbar and footer can be customized by the `params.navbar.width` and `params.footer.width` parameters.
|
||||||
|
|
||||||
|
### Search Index
|
||||||
|
|
||||||
|
Full-text search powered by [FlexSearch](https://github.com/nextapps-de/flexsearch) is enabled by default.
|
||||||
|
To customize the search index, set the `params.search.flexsearch.index` parameter in the config file:
|
||||||
|
|
||||||
|
```yaml {filename="hugo.yaml"}
|
||||||
|
params:
|
||||||
|
# Search
|
||||||
|
search:
|
||||||
|
enable: true
|
||||||
|
type: flexsearch
|
||||||
|
|
||||||
|
flexsearch:
|
||||||
|
# index page by: content | summary | heading | title
|
||||||
|
index: content
|
||||||
|
```
|
||||||
|
|
||||||
|
Options for `flexsearch.index`:
|
||||||
|
|
||||||
|
- `content` - full content of the page (default)
|
||||||
|
- `summary` - summary of the page, see [Hugo Content Summaries](https://gohugo.io/content-management/summaries/) for more details
|
||||||
|
- `heading` - level 1 and level 2 headings
|
||||||
|
- `title` - only include the page title
|
||||||
|
|
||||||
|
To exclude a page from the search index, set the `excludeSearch: true` in the front matter of the page:
|
||||||
|
|
||||||
|
```yaml {filename="content/docs/guide/configuration.md"}
|
||||||
|
---
|
||||||
|
title: Configuration
|
||||||
|
excludeSearch: true
|
||||||
|
---
|
||||||
|
```
|
||||||
|
|
||||||
### Google Analytics
|
### Google Analytics
|
||||||
|
|
||||||
|
@ -26,6 +26,7 @@ languages:
|
|||||||
title: "Hextra テーマ"
|
title: "Hextra テーマ"
|
||||||
zh-cn:
|
zh-cn:
|
||||||
languageName: 简体中文
|
languageName: 简体中文
|
||||||
|
languageCode: zh-CN
|
||||||
weight: 3
|
weight: 3
|
||||||
title: Hextra
|
title: Hextra
|
||||||
|
|
||||||
@ -108,6 +109,11 @@ params:
|
|||||||
# full (100%), wide (90rem), normal (1280px)
|
# full (100%), wide (90rem), normal (1280px)
|
||||||
width: normal
|
width: normal
|
||||||
|
|
||||||
|
theme:
|
||||||
|
# light | dark | system
|
||||||
|
default: system
|
||||||
|
displayToggle: true
|
||||||
|
|
||||||
footer:
|
footer:
|
||||||
displayCopyright: true
|
displayCopyright: true
|
||||||
displayPoweredBy: true
|
displayPoweredBy: true
|
||||||
@ -116,9 +122,33 @@ params:
|
|||||||
displayUpdatedDate: true
|
displayUpdatedDate: true
|
||||||
dateFormat: "January 2, 2006"
|
dateFormat: "January 2, 2006"
|
||||||
|
|
||||||
|
# Search
|
||||||
|
# flexsearch is enabled by default
|
||||||
search:
|
search:
|
||||||
enable: true
|
enable: true
|
||||||
|
type: flexsearch
|
||||||
|
|
||||||
|
flexsearch:
|
||||||
|
# index page by: content | summary | heading | title
|
||||||
|
index: content
|
||||||
|
|
||||||
editURL:
|
editURL:
|
||||||
enable: true
|
enable: true
|
||||||
base: "https://github.com/imfing/hextra/edit/main/exampleSite/content"
|
base: "https://github.com/imfing/hextra/edit/main/exampleSite/content"
|
||||||
|
|
||||||
|
comments:
|
||||||
|
enable: false
|
||||||
|
type: giscus
|
||||||
|
|
||||||
|
# https://giscus.app/
|
||||||
|
giscus:
|
||||||
|
repo: imfing/hextra
|
||||||
|
repoId: R_kgDOJ9fJag
|
||||||
|
category: General
|
||||||
|
categoryId: DIC_kwDOJ9fJas4CY7gW
|
||||||
|
# mapping: pathname
|
||||||
|
# strict: 0
|
||||||
|
# reactionsEnabled: 1
|
||||||
|
# emitMetadata: 0
|
||||||
|
# inputPosition: top
|
||||||
|
# lang: en
|
||||||
|
@ -112,6 +112,7 @@
|
|||||||
"border-black/5",
|
"border-black/5",
|
||||||
"border-blue-200",
|
"border-blue-200",
|
||||||
"border-gray-200",
|
"border-gray-200",
|
||||||
|
"border-gray-500",
|
||||||
"border-l",
|
"border-l",
|
||||||
"border-orange-100",
|
"border-orange-100",
|
||||||
"border-red-200",
|
"border-red-200",
|
||||||
@ -127,6 +128,7 @@
|
|||||||
"content",
|
"content",
|
||||||
"contrast-more:border",
|
"contrast-more:border",
|
||||||
"contrast-more:border-current",
|
"contrast-more:border-current",
|
||||||
|
"contrast-more:border-gray-800",
|
||||||
"contrast-more:border-gray-900",
|
"contrast-more:border-gray-900",
|
||||||
"contrast-more:border-neutral-400",
|
"contrast-more:border-neutral-400",
|
||||||
"contrast-more:border-primary-500",
|
"contrast-more:border-primary-500",
|
||||||
@ -152,6 +154,7 @@
|
|||||||
"contrast-more:text-gray-800",
|
"contrast-more:text-gray-800",
|
||||||
"contrast-more:text-gray-900",
|
"contrast-more:text-gray-900",
|
||||||
"contrast-more:underline",
|
"contrast-more:underline",
|
||||||
|
"copy-icon",
|
||||||
"cursor-default",
|
"cursor-default",
|
||||||
"cursor-pointer",
|
"cursor-pointer",
|
||||||
"dark:before:bg-neutral-800",
|
"dark:before:bg-neutral-800",
|
||||||
@ -171,6 +174,7 @@
|
|||||||
"dark:block",
|
"dark:block",
|
||||||
"dark:border-blue-200/30",
|
"dark:border-blue-200/30",
|
||||||
"dark:border-gray-100/20",
|
"dark:border-gray-100/20",
|
||||||
|
"dark:border-gray-400",
|
||||||
"dark:border-neutral-700",
|
"dark:border-neutral-700",
|
||||||
"dark:border-neutral-800",
|
"dark:border-neutral-800",
|
||||||
"dark:border-orange-400/30",
|
"dark:border-orange-400/30",
|
||||||
@ -188,6 +192,7 @@
|
|||||||
"dark:hover:bg-neutral-900",
|
"dark:hover:bg-neutral-900",
|
||||||
"dark:hover:bg-primary-100/5",
|
"dark:hover:bg-primary-100/5",
|
||||||
"dark:hover:bg-primary-700",
|
"dark:hover:bg-primary-700",
|
||||||
|
"dark:hover:border-gray-100",
|
||||||
"dark:hover:border-gray-600",
|
"dark:hover:border-gray-600",
|
||||||
"dark:hover:border-neutral-500",
|
"dark:hover:border-neutral-500",
|
||||||
"dark:hover:border-neutral-700",
|
"dark:hover:border-neutral-700",
|
||||||
@ -226,6 +231,7 @@
|
|||||||
"data-[state=selected]:text-primary-600",
|
"data-[state=selected]:text-primary-600",
|
||||||
"decoration-from-font",
|
"decoration-from-font",
|
||||||
"duration-200",
|
"duration-200",
|
||||||
|
"duration-75",
|
||||||
"ease-in",
|
"ease-in",
|
||||||
"ease-in-out",
|
"ease-in-out",
|
||||||
"filename",
|
"filename",
|
||||||
@ -264,6 +270,7 @@
|
|||||||
"h-0",
|
"h-0",
|
||||||
"h-16",
|
"h-16",
|
||||||
"h-2",
|
"h-2",
|
||||||
|
"h-3.5",
|
||||||
"h-4",
|
"h-4",
|
||||||
"h-5",
|
"h-5",
|
||||||
"h-7",
|
"h-7",
|
||||||
@ -289,6 +296,7 @@
|
|||||||
"hover:border-gray-200",
|
"hover:border-gray-200",
|
||||||
"hover:border-gray-300",
|
"hover:border-gray-300",
|
||||||
"hover:border-gray-400",
|
"hover:border-gray-400",
|
||||||
|
"hover:border-gray-900",
|
||||||
"hover:dark:bg-primary-500/10",
|
"hover:dark:bg-primary-500/10",
|
||||||
"hover:dark:text-primary-600",
|
"hover:dark:text-primary-600",
|
||||||
"hover:opacity-60",
|
"hover:opacity-60",
|
||||||
|
10
i18n/en.yaml
10
i18n/en.yaml
@ -1,5 +1,9 @@
|
|||||||
onThisPage: "On this page"
|
backToTop: "Scroll to top"
|
||||||
|
changeLanguage: "Change language"
|
||||||
|
changeTheme: "Change theme"
|
||||||
|
copyright: "© 2023 Hextra Project."
|
||||||
editThisPage: "Edit this page on GitHub →"
|
editThisPage: "Edit this page on GitHub →"
|
||||||
lastUpdated: "Last updated on"
|
lastUpdated: "Last updated on"
|
||||||
|
onThisPage: "On this page"
|
||||||
copyright: "© 2023 Hextra Project."
|
readMore: "Read more →"
|
||||||
|
searchPlaceholder: "Search..."
|
||||||
|
7
i18n/es.yaml
Normal file
7
i18n/es.yaml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
onThisPage: "En esta página"
|
||||||
|
editThisPage: "Edita esta página en GitHub →"
|
||||||
|
lastUpdated: "Última actualización"
|
||||||
|
|
||||||
|
backToTop: "Subir al inicio"
|
||||||
|
|
||||||
|
copyright: "© 2023 Hextra Project."
|
9
i18n/ko.yaml
Normal file
9
i18n/ko.yaml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
backToTop: "맨위로 스크롤"
|
||||||
|
changeLanguage: "언어변경"
|
||||||
|
changeTheme: "테마변경"
|
||||||
|
copyright: "© 2023 Hextra Project."
|
||||||
|
editThisPage: "Github에서 편집하기 →"
|
||||||
|
lastUpdated: "마지막 수정일자"
|
||||||
|
onThisPage: "페이지 목차"
|
||||||
|
readMore: "더보기 →"
|
||||||
|
searchPlaceholder: "검색..."
|
7
i18n/pt.yaml
Normal file
7
i18n/pt.yaml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
onThisPage: "Nesta página"
|
||||||
|
editThisPage: "Edita esta página no GitHub →"
|
||||||
|
lastUpdated: "Última actualização"
|
||||||
|
|
||||||
|
backToTop: "Voltar ao topo"
|
||||||
|
|
||||||
|
copyright: "© 2023 Projecto Hextra."
|
5
i18n/sw.yaml
Normal file
5
i18n/sw.yaml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
onThisPage: "Kwenye ukurasa huu"
|
||||||
|
editThisPage: "Hariri ukurasa huu kwenye GitHub →"
|
||||||
|
lastUpdated: "Ilisasishwa mwisho"
|
||||||
|
backToTop: "Tembeza hadi juu"
|
||||||
|
copyright: "© 2023 Hextra Project."
|
7
i18n/vi.yaml
Normal file
7
i18n/vi.yaml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
onThisPage: "Ở trang này"
|
||||||
|
editThisPage: "Sửa trang này trên GitHub →"
|
||||||
|
lastUpdated: "Lần cuối cập nhật lúc"
|
||||||
|
|
||||||
|
backToTop: "Lướt lên đầu trang"
|
||||||
|
|
||||||
|
copyright: "© 2023 Hextra Project."
|
@ -12,4 +12,6 @@ onThisPage: "此页上"
|
|||||||
editThisPage: "在 GitHub 上编辑此页 →"
|
editThisPage: "在 GitHub 上编辑此页 →"
|
||||||
lastUpdated: "最后更新于"
|
lastUpdated: "最后更新于"
|
||||||
|
|
||||||
|
backToTop: "返回顶部"
|
||||||
|
|
||||||
copyright: "© 2023 Hextra Project."
|
copyright: "© 2023 Hextra Project."
|
||||||
|
@ -15,9 +15,13 @@
|
|||||||
<pre><code id="code-block-{{ .Ordinal }}">{{ .Inner }}</code></pre>
|
<pre><code id="code-block-{{ .Ordinal }}">{{ .Inner }}</code></pre>
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
<div class="opacity-0 transition group-hover/code:opacity-100 flex gap-1 absolute m-[11px] right-0 {{ if $filename }}top-8{{ else }}top-0{{ end }}">
|
<div class="opacity-0 transition group-hover/code:opacity-100 flex gap-1 absolute m-[11px] right-0 {{ if $filename }}top-8{{ else }}top-0{{ end }}">
|
||||||
<button class="code-copy-btn group/copybtn transition-all active:opacity-50 bg-primary-700/5 border border-black/5 text-gray-600 hover:text-gray-900 rounded-md p-1.5 dark:bg-primary-300/10 dark:border-white/10 dark:text-gray-400 dark:hover:text-gray-50" title="Copy code" data-clipboard-target="#code-block-{{ .Ordinal }}">
|
<button
|
||||||
{{ partial "utils/icon.html" (dict "name" "copy" "attributes" "class=\"group-[.copied]/copybtn:hidden pointer-events-none h-4 w-4\"") }}
|
class="code-copy-btn group/copybtn transition-all active:opacity-50 bg-primary-700/5 border border-black/5 text-gray-600 hover:text-gray-900 rounded-md p-1.5 dark:bg-primary-300/10 dark:border-white/10 dark:text-gray-400 dark:hover:text-gray-50"
|
||||||
{{ partial "utils/icon.html" (dict "name" "check" "attributes" "class=\"hidden group-[.copied]/copybtn:block success-icon pointer-events-none h-4 w-4\"") }}
|
title="Copy code"
|
||||||
|
data-clipboard-target="#code-block-{{ .Ordinal }}"
|
||||||
|
>
|
||||||
|
<div class="group-[.copied]/copybtn:hidden copy-icon pointer-events-none h-4 w-4"></div>
|
||||||
|
<div class="hidden group-[.copied]/copybtn:block success-icon pointer-events-none h-4 w-4"></div>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="{{ .Site.Language.Lang }}">
|
<html lang="{{ .Site.Language.Lang }}">
|
||||||
{{- partial "head.html" . -}}
|
{{ partial "head.html" . -}}
|
||||||
<body dir="ltr">
|
<body dir="ltr">
|
||||||
{{- partial "navbar.html" . -}}
|
{{ partial "navbar.html" . -}}
|
||||||
{{- block "main" . }}{{ end -}}
|
{{- block "main" . }}{{ end -}}
|
||||||
{{- if (.Site.Params.footer.enable | default true) }}{{ partial "footer.html" . }}{{ end }}
|
{{- if or (eq .Site.Params.footer.enable nil) (.Site.Params.footer.enable) }}
|
||||||
|
{{ partial "footer.html" . }}
|
||||||
|
{{ end -}}
|
||||||
</body>
|
</body>
|
||||||
{{ partial "scripts.html" . }}
|
{{ partialCached "scripts.html" . }}
|
||||||
|
{{ partial "third-party/scripts.html" . }}
|
||||||
</html>
|
</html>
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="mt-16"></div>
|
<div class="mt-16"></div>
|
||||||
{{ partial "components/last-updated.html" . }}
|
{{ partial "components/last-updated.html" . }}
|
||||||
|
{{ partial "components/comments.html" . }}
|
||||||
</main>
|
</main>
|
||||||
</article>
|
</article>
|
||||||
</div>
|
</div>
|
||||||
|
@ -10,6 +10,8 @@
|
|||||||
<div class="content">
|
<div class="content">
|
||||||
{{ .Content }}
|
{{ .Content }}
|
||||||
</div>
|
</div>
|
||||||
|
<div class="mt-16"></div>
|
||||||
|
{{ partial "components/comments.html" . }}
|
||||||
</main>
|
</main>
|
||||||
</article>
|
</article>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
{{ define "main" }}
|
{{ define "main" }}
|
||||||
|
{{- $readMore := (T "readMore") | default "Read more →" -}}
|
||||||
<div class='mx-auto flex {{ partial "utils/page-width" . }}'>
|
<div class='mx-auto flex {{ partial "utils/page-width" . }}'>
|
||||||
{{ partial "sidebar.html" (dict "context" . "disableSidebar" true "displayPlaceholder" true) }}
|
{{ partial "sidebar.html" (dict "context" . "disableSidebar" true "displayPlaceholder" true) }}
|
||||||
<article class="w-full break-words flex min-h-[calc(100vh-var(--navbar-height))] min-w-0 justify-center pb-8 pr-[calc(env(safe-area-inset-right)-1.5rem)]">
|
<article class="w-full break-words flex min-h-[calc(100vh-var(--navbar-height))] min-w-0 justify-center pb-8 pr-[calc(env(safe-area-inset-right)-1.5rem)]">
|
||||||
@ -11,7 +12,7 @@
|
|||||||
<h3><a style="color: inherit; text-decoration: none;" class="block font-semibold mt-8 text-2xl " href="{{ .RelPermalink }}">{{ .Title }}</a></h3>
|
<h3><a style="color: inherit; text-decoration: none;" class="block font-semibold mt-8 text-2xl " href="{{ .RelPermalink }}">{{ .Title }}</a></h3>
|
||||||
<p class="opacity-80 mt-6 leading-7">
|
<p class="opacity-80 mt-6 leading-7">
|
||||||
{{- partial "utils/page-description" . }}
|
{{- partial "utils/page-description" . }}
|
||||||
<span class="inline-block"> <a class="text-[color:hsl(var(--primary-hue),100%,50%)] underline underline-offset-2 decoration-from-font" href="{{ .RelPermalink }}">Read more →</a> </span>
|
<span class="inline-block"> <a class="text-[color:hsl(var(--primary-hue),100%,50%)] underline underline-offset-2 decoration-from-font" href="{{ .RelPermalink }}">{{ $readMore }}</a> </span>
|
||||||
</p>
|
</p>
|
||||||
<p class="opacity-50 text-sm mt-6 leading-7">{{ partial "utils/format-date" .Date }}</p>
|
<p class="opacity-50 text-sm mt-6 leading-7">{{ partial "utils/format-date" .Date }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
{{ partial "components/last-updated.html" . }}
|
{{ partial "components/last-updated.html" . }}
|
||||||
{{ .Scratch.Set "reversePagination" true }}
|
{{ .Scratch.Set "reversePagination" true }}
|
||||||
{{ partial "components/pager.html" . }}
|
{{ partial "components/pager.html" . }}
|
||||||
|
{{ partial "components/comments.html" . }}
|
||||||
</main>
|
</main>
|
||||||
</article>
|
</article>
|
||||||
</div>
|
</div>
|
||||||
|
@ -9,9 +9,9 @@
|
|||||||
<h1>{{ .Title }}</h1>
|
<h1>{{ .Title }}</h1>
|
||||||
{{ .Content }}
|
{{ .Content }}
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-16"></div>
|
|
||||||
{{ partial "components/last-updated.html" . }}
|
{{ partial "components/last-updated.html" . }}
|
||||||
{{ partial "components/pager.html" . }}
|
{{ partial "components/pager.html" . }}
|
||||||
|
{{ partial "components/comments.html" . }}
|
||||||
</main>
|
</main>
|
||||||
</article>
|
</article>
|
||||||
</div>
|
</div>
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{{ partial "components/last-updated.html" . }}
|
{{ partial "components/last-updated.html" . }}
|
||||||
{{ partial "components/pager.html" . }}
|
{{ partial "components/pager.html" . }}
|
||||||
|
{{ partial "components/comments.html" . }}
|
||||||
</main>
|
</main>
|
||||||
</article>
|
</article>
|
||||||
</div>
|
</div>
|
||||||
|
11
layouts/partials/components/comments.html
Normal file
11
layouts/partials/components/comments.html
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{{- $enableComments := site.Params.comments.enable | default false -}}
|
||||||
|
|
||||||
|
{{ if not (eq .Params.comments nil) }}
|
||||||
|
{{ $enableComments = .Params.comments }}
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{- if $enableComments -}}
|
||||||
|
{{- if eq site.Params.comments.type "giscus" -}}
|
||||||
|
{{ partial "components/giscus.html" . }}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
62
layouts/partials/components/giscus.html
Normal file
62
layouts/partials/components/giscus.html
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
{{- $lang := site.Language.LanguageCode | default `en` -}}
|
||||||
|
|
||||||
|
{{- with site.Params.comments.giscus -}}
|
||||||
|
<script>
|
||||||
|
/*
|
||||||
|
* "preferred color scheme" theme in giscus works using "prefers-color-scheme" in media query.
|
||||||
|
* but, hugo's theme switch function works by using "color-theme" in local storage.
|
||||||
|
* This solution was created with reference to:
|
||||||
|
* https://github.com/giscus/giscus/issues/336#issuecomment-1214366281
|
||||||
|
*/
|
||||||
|
function getGiscusTheme() {
|
||||||
|
return localStorage.getItem("color-theme");
|
||||||
|
}
|
||||||
|
|
||||||
|
function setGiscusTheme() {
|
||||||
|
function sendMessage(message) {
|
||||||
|
const iframe = document.querySelector('iframe.giscus-frame');
|
||||||
|
if (!iframe) return;
|
||||||
|
iframe.contentWindow.postMessage({ giscus: message }, 'https://giscus.app');
|
||||||
|
}
|
||||||
|
sendMessage({
|
||||||
|
setConfig: {
|
||||||
|
theme: getGiscusTheme(),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
|
const giscusAttributes = {
|
||||||
|
"src": "https://giscus.app/client.js",
|
||||||
|
"data-repo": "{{ .repo }}",
|
||||||
|
"data-repo-id": "{{ .repoId }}",
|
||||||
|
"data-category": "{{ .category }}",
|
||||||
|
"data-category-id": "{{ .categoryId }}",
|
||||||
|
"data-mapping": "{{ .mapping | default `pathname` }}",
|
||||||
|
"data-strict": "{{ (string .strict) | default 0 }}",
|
||||||
|
"data-reactions-enabled": "{{ (string .reactionsEnabled) | default 1 }}",
|
||||||
|
"data-emit-metadata": "{{ (string .emitMetadata) | default 0 }}",
|
||||||
|
"data-input-position": "{{ .inputPosition | default `top` }}",
|
||||||
|
"data-theme": getGiscusTheme(),
|
||||||
|
"data-lang": "{{ .lang | default $lang }}",
|
||||||
|
"crossorigin": "anonymous",
|
||||||
|
"async": "",
|
||||||
|
};
|
||||||
|
|
||||||
|
// Dynamically create script tag
|
||||||
|
const giscusScript = document.createElement("script");
|
||||||
|
Object.entries(giscusAttributes).forEach(([key, value]) => giscusScript.setAttribute(key, value));
|
||||||
|
document.getElementById('giscus').appendChild(giscusScript);
|
||||||
|
|
||||||
|
// Update giscus theme when theme switcher is clicked
|
||||||
|
const toggles = document.querySelectorAll(".theme-toggle");
|
||||||
|
if (toggles) {
|
||||||
|
toggles.forEach(toggle => toggle.addEventListener('click', setGiscusTheme));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div id="giscus"></div>
|
||||||
|
{{- else -}}
|
||||||
|
{{ warnf "giscus is not configured" }}
|
||||||
|
{{- end -}}
|
@ -5,15 +5,23 @@
|
|||||||
{{- $prev := cond $reversePagination .PrevInSection .NextInSection -}}
|
{{- $prev := cond $reversePagination .PrevInSection .NextInSection -}}
|
||||||
{{- $next := cond $reversePagination .NextInSection .PrevInSection -}}
|
{{- $next := cond $reversePagination .NextInSection .PrevInSection -}}
|
||||||
|
|
||||||
{{- with .Params.prev -}}
|
{{- if eq .Params.prev false }}
|
||||||
{{- with $.Site.GetPage . -}}
|
{{- if $reversePagination }}{{ $next = false }}{{ else }}{{ $prev = false }}{{ end -}}
|
||||||
{{- if $reversePagination }}{{ $next = . }}{{ else }}{{ $prev = . }}{{ end -}}
|
{{ else }}
|
||||||
|
{{- with .Params.prev -}}
|
||||||
|
{{- with $.Site.GetPage . -}}
|
||||||
|
{{- if $reversePagination }}{{ $next = . }}{{ else }}{{ $prev = . }}{{ end -}}
|
||||||
|
{{- end -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{- with .Params.next -}}
|
{{- if eq .Params.next false }}
|
||||||
{{- with $.Site.GetPage . -}}
|
{{- if $reversePagination }}{{ $prev = false }}{{ else }}{{ $next = false }}{{ end -}}
|
||||||
{{- if $reversePagination }}{{ $prev = . }}{{ else }}{{ $next = . }}{{ end -}}
|
{{ else }}
|
||||||
|
{{- with .Params.next -}}
|
||||||
|
{{- with $.Site.GetPage . -}}
|
||||||
|
{{- if $reversePagination }}{{ $prev = . }}{{ else }}{{ $next = . }}{{ end -}}
|
||||||
|
{{- end -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
{{- $enableFooterSwitches := .Scratch.Get "enableFooterSwitches" | default false -}}
|
{{- $enableFooterSwitches := .Scratch.Get "enableFooterSwitches" | default false -}}
|
||||||
|
{{- $displayThemeToggle := site.Params.theme.displayToggle | default true -}}
|
||||||
|
|
||||||
{{- $copyright := (T "copyright") | default "© 2023 Hextra." -}}
|
{{- $copyright := (T "copyright") | default "© 2023 Hextra." -}}
|
||||||
|
|
||||||
@ -11,20 +12,23 @@
|
|||||||
{{ end -}}
|
{{ end -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
|
|
||||||
<footer class="hextra-footer bg-gray-100 pb-[env(safe-area-inset-bottom)] dark:bg-neutral-900 print:bg-transparent">
|
<footer class="hextra-footer bg-gray-100 pb-[env(safe-area-inset-bottom)] dark:bg-neutral-900 print:bg-transparent">
|
||||||
{{- if $enableFooterSwitches }}
|
{{- if $enableFooterSwitches -}}
|
||||||
<div class='mx-auto flex gap-2 py-2 px-4 {{ $footerWidth }}'>
|
<div class="mx-auto flex gap-2 py-2 px-4 {{ $footerWidth }}">
|
||||||
{{- partial "language-switch.html" (dict "context" .) -}}
|
{{- partial "language-switch.html" (dict "context" .) -}}
|
||||||
{{- partial "theme-toggle.html" -}}
|
{{- with $displayThemeToggle }}{{ partial "theme-toggle.html" }}{{ end -}}
|
||||||
</div>
|
</div>
|
||||||
{{ end -}}
|
{{- if or site.IsMultiLingual $displayThemeToggle -}}
|
||||||
<hr class="dark:border-neutral-800" />
|
<hr class="dark:border-neutral-800" />
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
<div
|
<div
|
||||||
class='{{ $footerWidth }} mx-auto flex justify-center py-12 pl-[max(env(safe-area-inset-left),1.5rem)] pr-[max(env(safe-area-inset-right),1.5rem)] text-gray-600 dark:text-gray-400 md:justify-start'
|
class="{{ $footerWidth }} mx-auto flex justify-center py-12 pl-[max(env(safe-area-inset-left),1.5rem)] pr-[max(env(safe-area-inset-right),1.5rem)] text-gray-600 dark:text-gray-400 md:justify-start"
|
||||||
>
|
>
|
||||||
<div class="flex w-full flex-col items-center sm:items-start">
|
<div class="flex w-full flex-col items-center sm:items-start">
|
||||||
{{- if (.Site.Params.footer.displayPoweredBy | default true) }}<div class="font-semibold">{{ template "theme-credit" . }}</div>{{ end }}
|
{{- if (.Site.Params.footer.displayPoweredBy | default true) }}<div class="font-semibold">{{ template "theme-credit" . }}</div>{{ end }}
|
||||||
{{- if .Site.Params.footer.displayCopyright }}<p class="mt-6 text-xs">{{ $copyright | markdownify }}</p>{{ end }}
|
{{- if .Site.Params.footer.displayCopyright }}<div class="mt-6 text-xs">{{ $copyright | markdownify }}</div>{{ end }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
@ -33,13 +33,25 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
/* Initialize light/dark mode */
|
/* Initialize light/dark mode */
|
||||||
if (localStorage.getItem("color-theme") === "dark" || (!("color-theme" in localStorage) && window.matchMedia("(prefers-color-scheme: dark)").matches)) {
|
const defaultTheme = '{{ site.Params.theme.default | default `system`}}';
|
||||||
|
|
||||||
|
const setDarkTheme = () => {
|
||||||
document.documentElement.classList.add("dark");
|
document.documentElement.classList.add("dark");
|
||||||
document.documentElement.style.colorScheme = "dark";
|
document.documentElement.style.colorScheme = "dark";
|
||||||
} else {
|
}
|
||||||
|
const setLightTheme = () => {
|
||||||
document.documentElement.classList.remove("dark");
|
document.documentElement.classList.remove("dark");
|
||||||
document.documentElement.style.colorScheme = "light";
|
document.documentElement.style.colorScheme = "light";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ("color-theme" in localStorage) {
|
||||||
|
localStorage.getItem("color-theme") === "dark" ? setDarkTheme() : setLightTheme();
|
||||||
|
} else {
|
||||||
|
defaultTheme === "dark" ? setDarkTheme() : setLightTheme();
|
||||||
|
if (defaultTheme === "system") {
|
||||||
|
window.matchMedia("(prefers-color-scheme: dark)").matches ? setDarkTheme() : setLightTheme();
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{{ partial "custom/head-end.html" . }}
|
{{ partial "custom/head-end.html" . }}
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
{{- $currentPage := . -}}
|
{{- $currentPage := . -}}
|
||||||
{{- range .Site.Menus.main -}}
|
{{- range .Site.Menus.main -}}
|
||||||
{{- if eq .Params.type "search" -}}
|
{{- if eq .Params.type "search" -}}
|
||||||
{{- partial "search.html" (dict "params" .Params) -}}
|
{{- partialCached "search.html" $currentPage -}}
|
||||||
{{- else -}}
|
{{- else -}}
|
||||||
{{- $external := strings.HasPrefix .URL "http" -}}
|
{{- $external := strings.HasPrefix .URL "http" -}}
|
||||||
{{/* Display icon menu item */}}
|
{{/* Display icon menu item */}}
|
||||||
|
@ -1,68 +1,32 @@
|
|||||||
{{- $jsTheme := resources.Get "js/theme.js" -}}
|
{{- $jsTheme := resources.Get "js/theme.js" | resources.ExecuteAsTemplate "theme.js" . -}}
|
||||||
{{- $jsMenu := resources.Get "js/menu.js" -}}
|
{{- $jsMenu := resources.Get "js/menu.js" -}}
|
||||||
{{- $jsTabs := resources.Get "js/tabs.js" -}}
|
{{- $jsTabs := resources.Get "js/tabs.js" -}}
|
||||||
{{- $jsLang := resources.Get "js/lang.js" -}}
|
{{- $jsLang := resources.Get "js/lang.js" -}}
|
||||||
{{- $jsCodeCopy := resources.Get "js/code-copy.js" -}}
|
{{- $jsCodeCopy := resources.Get "js/code-copy.js" -}}
|
||||||
{{- $jsFileTree := resources.Get "js/filetree.js" -}}
|
{{- $jsFileTree := resources.Get "js/filetree.js" -}}
|
||||||
{{- $jsSidebar := resources.Get "js/sidebar.js" -}}
|
{{- $jsSidebar := resources.Get "js/sidebar.js" -}}
|
||||||
|
{{- $jsBackToTop := resources.Get "js/back-to-top.js" -}}
|
||||||
|
|
||||||
{{- $scripts := slice $jsTheme $jsMenu $jsCodeCopy $jsTabs $jsLang $jsFileTree $jsSidebar | resources.Concat "js/main.js" -}}
|
{{- $scripts := slice $jsTheme $jsMenu $jsCodeCopy $jsTabs $jsLang $jsFileTree $jsSidebar $jsBackToTop | resources.Concat "js/main.js" -}}
|
||||||
{{- if hugo.IsProduction -}}
|
{{- if hugo.IsProduction -}}
|
||||||
{{- $scripts = $scripts | minify | fingerprint -}}
|
{{- $scripts = $scripts | minify | fingerprint -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
<script defer src="{{ $scripts.RelPermalink }}" integrity="{{ $scripts.Data.Integrity }}"></script>
|
<script defer src="{{ $scripts.RelPermalink }}" integrity="{{ $scripts.Data.Integrity }}"></script>
|
||||||
|
|
||||||
{{/* FlexSearch */}}
|
|
||||||
|
{{/* Search */}}
|
||||||
{{- if (site.Params.search.enable | default true) -}}
|
{{- if (site.Params.search.enable | default true) -}}
|
||||||
{{- $jsSearchScript := printf "%s.search.js" .Language.Lang -}}
|
{{- $searchType := site.Params.search.type | default "flexsearch" -}}
|
||||||
{{- $jsSearch := resources.Get "js/flexsearch.js" | resources.ExecuteAsTemplate $jsSearchScript . -}}
|
{{- if eq $searchType "flexsearch" -}}
|
||||||
{{- if hugo.IsProduction -}}
|
{{- $jsSearchScript := printf "%s.search.js" .Language.Lang -}}
|
||||||
{{- $jsSearch = $jsSearch | minify | fingerprint -}}
|
{{- $jsSearch := resources.Get "js/flexsearch.js" | resources.ExecuteAsTemplate $jsSearchScript . -}}
|
||||||
|
{{- if hugo.IsProduction -}}
|
||||||
|
{{- $jsSearch = $jsSearch | minify | fingerprint -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- $flexSearchJS := resources.Get "lib/flexsearch/flexsearch.bundle.min.js" | fingerprint -}}
|
||||||
|
<script defer src="{{ $flexSearchJS.RelPermalink }}" integrity="{{ $flexSearchJS.Data.Integrity }}"></script>
|
||||||
|
<script defer src="{{ $jsSearch.RelPermalink }}" integrity="{{ $jsSearch.Data.Integrity }}"></script>
|
||||||
|
{{- else -}}
|
||||||
|
{{- errorf `search type "%s" is not supported` $searchType -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
{{- $flexSearchJS := resources.Get "lib/flexsearch/flexsearch.bundle.min.js" | fingerprint -}}
|
|
||||||
<script defer src="{{ $flexSearchJS.RelPermalink }}" integrity="{{ $flexSearchJS.Data.Integrity }}"></script>
|
|
||||||
<script defer src="{{ $jsSearch.RelPermalink }}" integrity="{{ $jsSearch.Data.Integrity }}"></script>
|
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{/* Mermaid */}}
|
|
||||||
{{/* FIXME: need to investigate .Page.Store hasMermaid is set for homepage */}}
|
|
||||||
{{- if and (.Page.Store.Get "hasMermaid") (not .Page.IsHome) -}}
|
|
||||||
{{- $mermaidJS := resources.Get "lib/mermaid/mermaid.min.js" | fingerprint -}}
|
|
||||||
<script defer src="{{ $mermaidJS.RelPermalink }}" integrity="{{ $mermaidJS.Data.Integrity }}"></script>
|
|
||||||
<script>
|
|
||||||
document.addEventListener("DOMContentLoaded", function () {
|
|
||||||
const theme = document.documentElement.classList.contains("dark") ? "dark" : "default";
|
|
||||||
mermaid.initialize({ startOnLoad: true, theme: theme });
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
{{- end -}}
|
|
||||||
|
|
||||||
{{/* KaTex */}}
|
|
||||||
{{- if .Page.Params.math -}}
|
|
||||||
{{- $katexCSS := resources.Get "lib/katex/katex.min.css" | fingerprint -}}
|
|
||||||
{{- $katexJS := resources.Get "lib/katex/katex.min.js" | fingerprint -}}
|
|
||||||
{{- $mhchemJS := resources.Get "lib/katex/mhchem.min.js" | fingerprint -}}
|
|
||||||
{{- $katexAutoRenderJS := resources.Get "lib/katex/auto-render.min.js" | fingerprint -}}
|
|
||||||
<link type="text/css" rel="stylesheet" href="{{ $katexCSS.RelPermalink }}" integrity="{{ $katexCSS.Data.Integrity }}" />
|
|
||||||
<script defer src="{{ $katexJS.RelPermalink }}" integrity="{{ $katexJS.Data.Integrity }}"></script>
|
|
||||||
<script defer src="{{ $katexAutoRenderJS.RelPermalink }}" integrity="{{ $katexAutoRenderJS.Data.Integrity }}"></script>
|
|
||||||
<script defer src="{{ $mhchemJS.RelPermalink }}" integrity="{{ $mhchemJS.Data.Integrity }}"></script>
|
|
||||||
{{ $katexFonts := resources.Match "lib/katex/fonts/*" }}
|
|
||||||
{{- range $katexFonts -}}
|
|
||||||
{{ .Publish }}
|
|
||||||
{{- end -}}
|
|
||||||
<script>
|
|
||||||
// TODO: make render options configurable
|
|
||||||
document.addEventListener("DOMContentLoaded", function () {
|
|
||||||
renderMathInElement(document.body, {
|
|
||||||
delimiters: [
|
|
||||||
{ left: "$$", right: "$$", display: true },
|
|
||||||
{ left: "$", right: "$", display: false },
|
|
||||||
{ left: "\\(", right: "\\)", display: false },
|
|
||||||
{ left: "\\[", right: "\\]", display: true },
|
|
||||||
],
|
|
||||||
throwOnError: false,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
{{ end }}
|
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
<kbd
|
<kbd
|
||||||
class="absolute my-1.5 select-none ltr:right-1.5 rtl:left-1.5 h-5 rounded bg-white px-1.5 font-mono text-[10px] font-medium text-gray-500 border dark:border-gray-100/20 dark:bg-dark/50 contrast-more:border-current contrast-more:text-current contrast-more:dark:border-current items-center gap-1 transition-opacity pointer-events-none hidden sm:flex"
|
class="absolute my-1.5 select-none ltr:right-1.5 rtl:left-1.5 h-5 rounded bg-white px-1.5 font-mono text-[10px] font-medium text-gray-500 border dark:border-gray-100/20 dark:bg-dark/50 contrast-more:border-current contrast-more:text-current contrast-more:dark:border-current items-center gap-1 transition-opacity pointer-events-none hidden sm:flex"
|
||||||
>
|
>
|
||||||
<span class="text-xs">⌘</span>K
|
CTRL K
|
||||||
</kbd>
|
</kbd>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -6,134 +6,40 @@
|
|||||||
{{- $sidebarClass := cond $disableSidebar (cond $displayPlaceholder "md:hidden xl:block" "md:hidden") "md:sticky" -}}
|
{{- $sidebarClass := cond $disableSidebar (cond $displayPlaceholder "md:hidden xl:block" "md:hidden") "md:sticky" -}}
|
||||||
|
|
||||||
{{- $navRoot := cond (eq site.Home.Type "docs") site.Home $context.FirstSection -}}
|
{{- $navRoot := cond (eq site.Home.Type "docs") site.Home $context.FirstSection -}}
|
||||||
{{- $navPages := union $navRoot.RegularPages $navRoot.Sections -}}
|
|
||||||
{{- $pageURL := $context.RelPermalink -}}
|
{{- $pageURL := $context.RelPermalink -}}
|
||||||
|
|
||||||
|
|
||||||
<aside class="sidebar-container flex flex-col print:hidden md:top-16 md:shrink-0 md:w-64 md:self-start max-md:[transform:translate3d(0,-100%,0)] {{ $sidebarClass }}">
|
<aside class="sidebar-container flex flex-col print:hidden md:top-16 md:shrink-0 md:w-64 md:self-start max-md:[transform:translate3d(0,-100%,0)] {{ $sidebarClass }}">
|
||||||
<!-- Search bar on small screen -->
|
{{/* Search bar on small screen */}}
|
||||||
<div class="px-4 pt-4 md:hidden">
|
{{- partialCached "sidebar/mobile-search" . -}}
|
||||||
{{ partial "search.html" }}
|
|
||||||
</div>
|
|
||||||
<div class="hextra-scrollbar overflow-y-auto overflow-x-hidden p-4 grow md:h-[calc(100vh-var(--navbar-height)-var(--menu-height))]">
|
<div class="hextra-scrollbar overflow-y-auto overflow-x-hidden p-4 grow md:h-[calc(100vh-var(--navbar-height)-var(--menu-height))]">
|
||||||
<ul class="flex flex-col gap-1 md:hidden">
|
<ul class="flex flex-col gap-1 md:hidden">
|
||||||
<!-- Nav -->
|
{{/* Mobile Navigation */}}
|
||||||
{{ template "sidebar-main" (dict "context" site.Home "pageURL" $pageURL "page" $context "toc" true) -}}
|
{{ $treeMobile := partialCached "sidebar/section-tree" site.Home site.Home }}
|
||||||
{{ template "sidebar-footer" }}
|
{{ partial "sidebar/render-tree" (dict "context" site.Home "page" $context "tree" ($treeMobile | unmarshal)) }}
|
||||||
|
{{ partialCached "sidebar/extra" $context }}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<!-- Sidebar on large screen -->
|
{{/* Sidebar on large screen */}}
|
||||||
{{- if $disableSidebar -}}
|
<ul class="flex flex-col gap-1 max-md:hidden">
|
||||||
{{- if $displayPlaceholder }}<div class="max-xl:hidden h-0 w-64 shrink-0"></div>{{ end -}}
|
{{ $tree := partialCached "sidebar/section-tree" $navRoot $navRoot }}
|
||||||
{{ .context.Scratch.Set "enableFooterSwitches" true }}
|
{{ partial "sidebar/render-tree" (dict "context" $navRoot "page" $context "tree" ($tree | unmarshal)) }}
|
||||||
{{- else -}}
|
{{ partialCached "sidebar/extra" $context }}
|
||||||
<ul class="flex flex-col gap-1 max-md:hidden">
|
</ul>
|
||||||
{{ template "sidebar-main" (dict "context" $navRoot "page" $context "pageURL" $pageURL) }}
|
|
||||||
{{ template "sidebar-footer" }}
|
|
||||||
</ul>
|
|
||||||
{{ end -}}
|
|
||||||
</div>
|
|
||||||
{{/* Hide theme switch when sidebar is disabled */}}
|
|
||||||
{{ $switchesClass := cond $disableSidebar "md:hidden" "" }}
|
|
||||||
<div class="{{ $switchesClass }} {{ with site.IsMultiLingual }}justify-end{{ end }} sticky bottom-0 bg-white dark:bg-dark mx-4 py-4 shadow-[0_-12px_16px_#fff] flex items-center gap-2 dark:border-neutral-800 dark:shadow-[0_-12px_16px_#111] contrast-more:border-neutral-400 contrast-more:shadow-none contrast-more:dark:shadow-none border-t" data-toggle-animation="show">
|
|
||||||
{{- with site.IsMultiLingual }}
|
|
||||||
{{ partial "language-switch" (dict "context" $context "grow" true) }}
|
|
||||||
{{ partial "theme-toggle" (dict "hideLabel" true) }}
|
|
||||||
{{ else }}
|
|
||||||
<div class="flex grow flex-col">
|
|
||||||
{{ partial "theme-toggle" }}
|
|
||||||
</div>
|
|
||||||
{{ end -}}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{{ partial "sidebar/switches" (dict "context" $context "disableSidebar" $disableSidebar) }}
|
||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
{{- define "sidebar-main" -}}
|
{{- define "partials/sidebar/mobile-search" -}}
|
||||||
{{ template "sidebar-tree" (dict "context" .context "level" 0 "page" .page "pageURL" .pageURL "toc" (.toc | default false)) }}
|
<div class="px-4 pt-4 md:hidden">
|
||||||
{{- end -}}
|
{{- partialCached "search.html" . -}}
|
||||||
|
</div>
|
||||||
{{- define "sidebar-tree" -}}
|
|
||||||
{{- if ge .level 4 -}}
|
|
||||||
{{- return -}}
|
|
||||||
{{- end -}}
|
|
||||||
|
|
||||||
{{- $context := .context -}}
|
|
||||||
{{- $page := .page }}
|
|
||||||
{{- $pageURL := .page.RelPermalink -}}
|
|
||||||
{{- $level := .level -}}
|
|
||||||
{{- $toc := .toc | default false -}}
|
|
||||||
|
|
||||||
{{- with $items := union .context.RegularPages .context.Sections -}}
|
|
||||||
{{- if eq $level 0 -}}
|
|
||||||
{{- range $items.ByWeight }}
|
|
||||||
{{- $active := eq $pageURL .RelPermalink -}}
|
|
||||||
{{- $shouldOpen := or (.Params.sidebar.open) (.IsAncestor $page) $active | default true }}
|
|
||||||
<li class="{{ if $shouldOpen }}open{{ end }}">
|
|
||||||
{{- template "sidebar-item-link" dict "context" . "active" $active "title" .LinkTitle "link" .RelPermalink -}}
|
|
||||||
{{- if and $toc $active -}}
|
|
||||||
{{- template "sidebar-toc" dict "page" . -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- template "sidebar-tree" dict "context" . "page" $page "pageURL" $pageURL "level" (add $level 1) "toc" $toc -}}
|
|
||||||
</li>
|
|
||||||
{{- end -}}
|
|
||||||
{{- else -}}
|
|
||||||
<div class="pt-1 ltr:pr-0 overflow-hidden transition-all ease-in-out duration-200">
|
|
||||||
<ul class='relative flex flex-col gap-1 before:absolute before:inset-y-1 before:w-px before:bg-gray-200 before:content-[""] ltr:ml-3 ltr:pl-3 ltr:before:left-0 rtl:mr-3 rtl:pr-3 rtl:before:right-0 dark:before:bg-neutral-800'>
|
|
||||||
{{- range $items.ByWeight }}
|
|
||||||
{{- $active := eq $pageURL .RelPermalink -}}
|
|
||||||
{{- $shouldOpen := or (.Params.sidebar.open) (.IsAncestor $page) $active | default true }}
|
|
||||||
{{- $title := .LinkTitle | default .File.BaseFileName -}}
|
|
||||||
<li class="flex flex-col gap-1 {{ if $shouldOpen }}open{{ end }}">
|
|
||||||
{{- template "sidebar-item-link" dict "context" . "active" $active "title" $title "link" .RelPermalink -}}
|
|
||||||
{{- if and $toc $active -}}
|
|
||||||
{{ template "sidebar-toc" dict "page" . }}
|
|
||||||
{{- end }}
|
|
||||||
{{ template "sidebar-tree" dict "context" . "page" $page "pageURL" $pageURL "level" (add $level 1) "toc" $toc }}
|
|
||||||
</li>
|
|
||||||
{{- end -}}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
{{- end -}}
|
|
||||||
{{- end }}
|
|
||||||
{{- end -}}
|
|
||||||
|
|
||||||
{{- define "sidebar-toc" -}}
|
|
||||||
{{ $page := .page }}
|
|
||||||
{{ with $page.Fragments.Headings }}
|
|
||||||
<ul class='flex flex-col gap-1 relative before:absolute before:inset-y-1 before:w-px before:bg-gray-200 before:content-[""] dark:before:bg-neutral-800 ltr:pl-3 ltr:before:left-0 rtl:pr-3 rtl:before:right-0 ltr:ml-3 rtl:mr-3'>
|
|
||||||
{{- range . }}
|
|
||||||
{{- with .Headings }}
|
|
||||||
{{- range . -}}
|
|
||||||
<li>
|
|
||||||
<a
|
|
||||||
href="#{{ anchorize .ID }}"
|
|
||||||
class="flex rounded px-2 py-1.5 text-sm transition-colors [word-break:break-word] cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:border flex gap-2 before:opacity-25 before:content-['#'] text-gray-500 hover:bg-gray-100 hover:text-gray-900 dark:text-neutral-400 dark:hover:bg-primary-100/5 dark:hover:text-gray-50 contrast-more:text-gray-900 contrast-more:dark:text-gray-50 contrast-more:border-transparent contrast-more:hover:border-gray-900 contrast-more:dark:hover:border-gray-50"
|
|
||||||
>
|
|
||||||
{{- .Title -}}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{{ end -}}
|
|
||||||
{{ end -}}
|
|
||||||
{{ end -}}
|
|
||||||
</ul>
|
|
||||||
{{ end }}
|
|
||||||
{{- end -}}
|
|
||||||
|
|
||||||
{{- define "sidebar-footer" -}}
|
|
||||||
{{- range site.Menus.sidebar -}}
|
|
||||||
{{- $name := or (T .Identifier) .Name -}}
|
|
||||||
{{ if eq .Params.type "separator" }}
|
|
||||||
<li class="[word-break:break-word] mt-5 mb-2 px-2 py-1.5 text-sm font-semibold text-gray-900 first:mt-0 dark:text-gray-100">
|
|
||||||
<span class="cursor-default">{{ $name }}</span>
|
|
||||||
</li>
|
|
||||||
{{ else }}
|
|
||||||
<li>{{ template "sidebar-item-link" dict "active" false "title" $name "link" (.URL | relLangURL) }}</li>
|
|
||||||
{{ end }}
|
|
||||||
{{- end -}}
|
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{- define "sidebar-item-link" -}}
|
{{- define "sidebar-item-link" -}}
|
||||||
{{- $external := strings.HasPrefix .link "http" -}}
|
{{- $external := strings.HasPrefix .link "http" -}}
|
||||||
{{- $open := .open | default true -}}
|
|
||||||
<a
|
<a
|
||||||
class="flex items-center justify-between gap-2 cursor-pointer rounded px-2 py-1.5 text-sm transition-colors [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] [word-break:break-word]
|
class="flex items-center justify-between gap-2 cursor-pointer rounded px-2 py-1.5 text-sm transition-colors [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] [word-break:break-word]
|
||||||
{{- if .active }}
|
{{- if .active }}
|
||||||
@ -144,21 +50,30 @@
|
|||||||
href="{{ .link }}"
|
href="{{ .link }}"
|
||||||
{{ if $external }}target="_blank" rel="noreferer"{{ end }}
|
{{ if $external }}target="_blank" rel="noreferer"{{ end }}
|
||||||
>
|
>
|
||||||
{{- .title -}}
|
{{- .title | htmlUnescape | safeHTML -}}
|
||||||
{{- with .context }}
|
{{- with .context }}
|
||||||
{{- if or .RegularPages .Sections }}
|
{{- if or .RegularPages .Sections .section }}{{ partialCached "sidebar/collapsible-button" . }}{{ end -}}
|
||||||
<span class="hextra-sidebar-collapsible-button">
|
|
||||||
{{- template "sidebear-collapsible-button" -}}
|
|
||||||
</span>
|
|
||||||
{{- end }}
|
|
||||||
{{ end -}}
|
{{ end -}}
|
||||||
</a>
|
</a>
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{- define "sidebar-separator" -}}
|
{{- define "partials/sidebar/switches" -}}
|
||||||
<div class="mt-4 border-t py-4 dark:border-neutral-800 contrast-more:border-neutral-400 dark:contrast-more:border-neutral-400" />
|
{{- $context := .context -}}
|
||||||
{{- end -}}
|
{{- $disableSidebar := .disableSidebar -}}
|
||||||
|
{{/* Hide theme switch when sidebar is disabled */}}
|
||||||
|
{{ $switchesClass := cond $disableSidebar "md:hidden" "" -}}
|
||||||
|
{{ $displayThemeToggle := (site.Params.theme.displayToggle | default true) -}}
|
||||||
|
|
||||||
{{- define "sidebear-collapsible-button" -}}
|
{{ if or site.IsMultiLingual $displayThemeToggle }}
|
||||||
<svg fill="none" viewBox="0 0 24 24" stroke="currentColor" class="h-[18px] min-w-[18px] rounded-sm p-0.5 hover:bg-gray-800/5 dark:hover:bg-gray-100/5"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" class="origin-center transition-transform rtl:-rotate-180"></path></svg>
|
<div class="{{ $switchesClass }} {{ with site.IsMultiLingual }}justify-end{{ end }} sticky bottom-0 bg-white dark:bg-dark mx-4 py-4 shadow-[0_-12px_16px_#fff] flex items-center gap-2 dark:border-neutral-800 dark:shadow-[0_-12px_16px_#111] contrast-more:border-neutral-400 contrast-more:shadow-none contrast-more:dark:shadow-none border-t" data-toggle-animation="show">
|
||||||
|
{{- with site.IsMultiLingual -}}
|
||||||
|
{{- partial "language-switch" (dict "context" $context "grow" true) -}}
|
||||||
|
{{- with $displayThemeToggle }}{{ partial "theme-toggle" (dict "hideLabel" true) }}{{ end -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- with $displayThemeToggle -}}
|
||||||
|
<div class="flex grow flex-col">{{ partial "theme-toggle" }}</div>
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
|
</div>
|
||||||
|
{{- end -}}
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
3
layouts/partials/sidebar/collapsible-button.html
Normal file
3
layouts/partials/sidebar/collapsible-button.html
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<span class="hextra-sidebar-collapsible-button">
|
||||||
|
<svg fill="none" viewBox="0 0 24 24" stroke="currentColor" class="h-[18px] min-w-[18px] rounded-sm p-0.5 hover:bg-gray-800/5 dark:hover:bg-gray-100/5"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" class="origin-center transition-transform rtl:-rotate-180"></path></svg>
|
||||||
|
</span>
|
10
layouts/partials/sidebar/extra.html
Normal file
10
layouts/partials/sidebar/extra.html
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{{- range site.Menus.sidebar -}}
|
||||||
|
{{- $name := or (T .Identifier) .Name -}}
|
||||||
|
{{ if eq .Params.type "separator" }}
|
||||||
|
<li class="[word-break:break-word] mt-5 mb-2 px-2 py-1.5 text-sm font-semibold text-gray-900 first:mt-0 dark:text-gray-100">
|
||||||
|
<span class="cursor-default">{{ $name }}</span>
|
||||||
|
</li>
|
||||||
|
{{ else }}
|
||||||
|
<li>{{ template "sidebar-item-link" (dict "active" false "title" $name "link" (.URL | relLangURL)) }}</li>
|
||||||
|
{{ end }}
|
||||||
|
{{- end -}}
|
@ -0,0 +1,15 @@
|
|||||||
|
{{- $entry := . -}}
|
||||||
|
|
||||||
|
<div class="pt-1 ltr:pr-0 overflow-hidden transition-all ease-in-out duration-200">
|
||||||
|
<ul class='relative flex flex-col gap-1 before:absolute before:inset-y-1 before:w-px before:bg-gray-200 before:content-[""] ltr:ml-3 ltr:pl-3 ltr:before:left-0 rtl:mr-3 rtl:pr-3 rtl:before:right-0 dark:before:bg-neutral-800'>
|
||||||
|
{{- range $entry }}
|
||||||
|
{{- $shouldOpen := .open | default false }}
|
||||||
|
<li class="flex flex-col gap-1 {{ if $shouldOpen }}open{{ end }}">
|
||||||
|
{{- template "sidebar-item-link" (dict "context" . "active" false "title" .title "link" .link) -}}
|
||||||
|
{{- if .section -}}
|
||||||
|
{{- partial "sidebar/render-tree-branch-without-leaf" .section -}}
|
||||||
|
{{- end -}}
|
||||||
|
</li>
|
||||||
|
{{- end -}}
|
||||||
|
</ul>
|
||||||
|
</div>
|
19
layouts/partials/sidebar/render-tree-branch.html
Normal file
19
layouts/partials/sidebar/render-tree-branch.html
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
{{- $context := .context -}}
|
||||||
|
{{- $page := .page -}}
|
||||||
|
{{- $entry := .entry -}}
|
||||||
|
{{- $pageLink := .page.RelPermalink -}}
|
||||||
|
|
||||||
|
<div class="pt-1 ltr:pr-0 overflow-hidden transition-all ease-in-out duration-200">
|
||||||
|
<ul class='relative flex flex-col gap-1 before:absolute before:inset-y-1 before:w-px before:bg-gray-200 before:content-[""] ltr:ml-3 ltr:pl-3 ltr:before:left-0 rtl:mr-3 rtl:pr-3 rtl:before:right-0 dark:before:bg-neutral-800'>
|
||||||
|
{{- range $entry }}
|
||||||
|
{{- $active := eq $pageLink .link -}}
|
||||||
|
{{- $shouldOpen := or (.open) (hasPrefix $pageLink .link) $active | default true }}
|
||||||
|
<li class="flex flex-col gap-1 {{ if $shouldOpen }}open{{ end }}">
|
||||||
|
{{- template "sidebar-item-link" (dict "context" . "active" $active "title" .title "link" .link) -}}
|
||||||
|
{{- if .section -}}
|
||||||
|
{{- partial "sidebar/render-tree-branch" (dict "context" $context "entry" .section "page" $page) -}}
|
||||||
|
{{- end -}}
|
||||||
|
</li>
|
||||||
|
{{- end -}}
|
||||||
|
</ul>
|
||||||
|
</div>
|
18
layouts/partials/sidebar/render-tree.html
Normal file
18
layouts/partials/sidebar/render-tree.html
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
{{- $context := .context -}}
|
||||||
|
{{- $page := .page -}}
|
||||||
|
{{- $pageLink := .page.RelPermalink -}}
|
||||||
|
{{- range .tree -}}
|
||||||
|
{{- $active := eq $pageLink .link -}}
|
||||||
|
{{- $containsPage := hasPrefix $pageLink .link -}}
|
||||||
|
{{- $shouldOpen := or (.open) $containsPage $active | default false }}
|
||||||
|
<li class="{{ if $shouldOpen }}open{{ end }}">
|
||||||
|
{{- template "sidebar-item-link" (dict "context" . "active" $active "title" .title "link" .link) -}}
|
||||||
|
{{- if .section -}}
|
||||||
|
{{- if not $containsPage -}}
|
||||||
|
{{- partialCached "sidebar/render-tree-branch-without-leaf" .section .section -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- partial "sidebar/render-tree-branch" (dict "context" $context "entry" .section "page" $page) -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
|
</li>
|
||||||
|
{{ end }}
|
51
layouts/partials/sidebar/section-tree.html
Normal file
51
layouts/partials/sidebar/section-tree.html
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
{{ $context := . -}}
|
||||||
|
|
||||||
|
{{- $pages := union .RegularPages .Sections -}}
|
||||||
|
{{- $pages = where $pages "Params.sidebar.exclude" "!=" true -}}
|
||||||
|
|
||||||
|
{{- $data := slice -}}
|
||||||
|
|
||||||
|
{{- range $pages.ByWeight -}}
|
||||||
|
{{ $structure := (partial "sidebar/section-walk" .) | unmarshal -}}
|
||||||
|
{{ $data = $data | append $structure -}}
|
||||||
|
{{ end -}}
|
||||||
|
|
||||||
|
{{- define "partials/sidebar/section-walk" -}}
|
||||||
|
{{- with . -}}
|
||||||
|
{
|
||||||
|
"title": "{{ .LinkTitle | default .File.BaseFileName }}",
|
||||||
|
"link": "{{ .RelPermalink }}",
|
||||||
|
"toc": {{ partial "sidebar/section-page-toc" . }},
|
||||||
|
"open": {{ .Params.sidebar.open | default false }}
|
||||||
|
{{- if .IsSection }},
|
||||||
|
"section": [
|
||||||
|
{{ $pages := union .RegularPages .Sections -}}
|
||||||
|
{{ $pages = where $pages "Params.sidebar.exclude" "!=" true -}}
|
||||||
|
{{ range $index, $page := $pages.ByWeight -}}
|
||||||
|
{{ partial "sidebar/section-walk" . }}{{ if not (ge $index (sub (len $pages) 1)) }},{{ end -}}
|
||||||
|
{{ end -}}
|
||||||
|
]
|
||||||
|
{{ end -}}
|
||||||
|
}
|
||||||
|
{{- end }}
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
|
{{- define "partials/sidebar/section-page-toc" -}}
|
||||||
|
{{/* Get level 2 headings list used mainly for mobile navigation */}}
|
||||||
|
[
|
||||||
|
{{- with .Fragments.Headings -}}
|
||||||
|
{{/* Loop over level 1 headings */}}
|
||||||
|
{{- range . }}
|
||||||
|
{{- with .Headings }}
|
||||||
|
{{ $headings := . }}
|
||||||
|
{{- range $index, $heading := $headings }}
|
||||||
|
{{ $heading.Title | jsonify (dict "noHTMLEscape" true) }}
|
||||||
|
{{- if not (ge $index (sub (len $headings) 1)) }},{{ end -}}
|
||||||
|
{{ end -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{ end -}}
|
||||||
|
{{- end -}}
|
||||||
|
]
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
|
{{ return ($data | jsonify (dict "noHTMLEscape" true)) }}
|
21
layouts/partials/sidebar/toc.html
Normal file
21
layouts/partials/sidebar/toc.html
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
{{ $page := . }}
|
||||||
|
{{ with $page.Fragments.Headings }}
|
||||||
|
<ul
|
||||||
|
class='flex flex-col gap-1 relative before:absolute before:inset-y-1 before:w-px before:bg-gray-200 before:content-[""] dark:before:bg-neutral-800 ltr:pl-3 ltr:before:left-0 rtl:pr-3 rtl:before:right-0 ltr:ml-3 rtl:mr-3'
|
||||||
|
>
|
||||||
|
{{- range . }}
|
||||||
|
{{- with .Headings }}
|
||||||
|
{{- range . -}}
|
||||||
|
<li>
|
||||||
|
<a
|
||||||
|
href="#{{ anchorize .ID }}"
|
||||||
|
class="flex rounded px-2 py-1.5 text-sm transition-colors [word-break:break-word] cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:border gap-2 before:opacity-25 before:content-['#'] text-gray-500 hover:bg-gray-100 hover:text-gray-900 dark:text-neutral-400 dark:hover:bg-primary-100/5 dark:hover:text-gray-50 contrast-more:text-gray-900 contrast-more:dark:text-gray-50 contrast-more:border-transparent contrast-more:hover:border-gray-900 contrast-more:dark:hover:border-gray-50"
|
||||||
|
>
|
||||||
|
{{- .Title -}}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{{ end -}}
|
||||||
|
{{ end -}}
|
||||||
|
{{ end -}}
|
||||||
|
</ul>
|
||||||
|
{{ end }}
|
42
layouts/partials/third-party/scripts.html
vendored
Normal file
42
layouts/partials/third-party/scripts.html
vendored
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
{{/* Mermaid */}}
|
||||||
|
{{/* FIXME: need to investigate .Page.Store hasMermaid is set for homepage */}}
|
||||||
|
{{- if and (.Page.Store.Get "hasMermaid") (not .Page.IsHome) -}}
|
||||||
|
{{- $mermaidJS := resources.Get "lib/mermaid/mermaid.min.js" | fingerprint -}}
|
||||||
|
<script defer src="{{ $mermaidJS.RelPermalink }}" integrity="{{ $mermaidJS.Data.Integrity }}"></script>
|
||||||
|
<script>
|
||||||
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
|
const theme = document.documentElement.classList.contains("dark") ? "dark" : "default";
|
||||||
|
mermaid.initialize({ startOnLoad: true, theme: theme });
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
|
{{/* KaTex */}}
|
||||||
|
{{- if .Page.Params.math -}}
|
||||||
|
{{- $katexCSS := resources.Get "lib/katex/katex.min.css" | fingerprint -}}
|
||||||
|
{{- $katexJS := resources.Get "lib/katex/katex.min.js" | fingerprint -}}
|
||||||
|
{{- $mhchemJS := resources.Get "lib/katex/mhchem.min.js" | fingerprint -}}
|
||||||
|
{{- $katexAutoRenderJS := resources.Get "lib/katex/auto-render.min.js" | fingerprint -}}
|
||||||
|
<link type="text/css" rel="stylesheet" href="{{ $katexCSS.RelPermalink }}" integrity="{{ $katexCSS.Data.Integrity }}" />
|
||||||
|
<script defer src="{{ $katexJS.RelPermalink }}" integrity="{{ $katexJS.Data.Integrity }}"></script>
|
||||||
|
<script defer src="{{ $katexAutoRenderJS.RelPermalink }}" integrity="{{ $katexAutoRenderJS.Data.Integrity }}"></script>
|
||||||
|
<script defer src="{{ $mhchemJS.RelPermalink }}" integrity="{{ $mhchemJS.Data.Integrity }}"></script>
|
||||||
|
{{ $katexFonts := resources.Match "lib/katex/fonts/*" }}
|
||||||
|
{{- range $katexFonts -}}
|
||||||
|
{{ .Publish }}
|
||||||
|
{{- end -}}
|
||||||
|
<script>
|
||||||
|
// TODO: make render options configurable
|
||||||
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
|
renderMathInElement(document.body, {
|
||||||
|
delimiters: [
|
||||||
|
{ left: "$$", right: "$$", display: true },
|
||||||
|
{ left: "$", right: "$", display: false },
|
||||||
|
{ left: "\\(", right: "\\)", display: false },
|
||||||
|
{ left: "\\[", right: "\\]", display: true },
|
||||||
|
],
|
||||||
|
throwOnError: false,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
{{ end }}
|
@ -3,6 +3,7 @@
|
|||||||
{{- $toc := .Params.toc | default true -}}
|
{{- $toc := .Params.toc | default true -}}
|
||||||
{{- $onThisPage := (T "onThisPage") | default "On this page"}}
|
{{- $onThisPage := (T "onThisPage") | default "On this page"}}
|
||||||
{{- $editThisPage := (T "editThisPage") | default "Edit this page"}}
|
{{- $editThisPage := (T "editThisPage") | default "Edit this page"}}
|
||||||
|
{{- $backToTop := (T "backToTop") | default "Scroll to top" -}}
|
||||||
|
|
||||||
<nav class="hextra-toc order-last hidden w-64 shrink-0 xl:block print:hidden px-4" aria-label="table of contents">
|
<nav class="hextra-toc order-last hidden w-64 shrink-0 xl:block print:hidden px-4" aria-label="table of contents">
|
||||||
{{- if $toc }}
|
{{- if $toc }}
|
||||||
@ -25,10 +26,19 @@
|
|||||||
<div class="{{ $borderClass }} sticky bottom-0 flex flex-col items-start gap-2 pb-8 dark:border-neutral-800 contrast-more:border-t contrast-more:border-neutral-400 contrast-more:shadow-none contrast-more:dark:border-neutral-400">
|
<div class="{{ $borderClass }} sticky bottom-0 flex flex-col items-start gap-2 pb-8 dark:border-neutral-800 contrast-more:border-t contrast-more:border-neutral-400 contrast-more:shadow-none contrast-more:dark:border-neutral-400">
|
||||||
{{- if site.Params.editURL.enable -}}
|
{{- if site.Params.editURL.enable -}}
|
||||||
{{- $editURL := site.Params.editURL.base | default "" -}}
|
{{- $editURL := site.Params.editURL.base | default "" -}}
|
||||||
{{- with .File -}}{{ $editURL = urls.JoinPath $editURL .Path }}{{- end -}}
|
{{- with .File -}}{{ $editURL = urls.JoinPath $editURL (replace .Path "\\" "/") }}{{- end -}}
|
||||||
{{- with .Params.editURL -}}{{ $editURL = .Params.editURL }}{{- end -}}
|
{{- with .Params.editURL -}}{{ $editURL = .Params.editURL }}{{- end -}}
|
||||||
<a class="text-xs font-medium text-gray-500 hover:text-gray-900 dark:text-gray-400 dark:hover:text-gray-100 contrast-more:text-gray-800 contrast-more:dark:text-gray-50" href="{{ $editURL }}" target="_blank" rel="noreferer">{{ $editThisPage }}</a>
|
<a class="text-xs font-medium text-gray-500 hover:text-gray-900 dark:text-gray-400 dark:hover:text-gray-100 contrast-more:text-gray-800 contrast-more:dark:text-gray-50" href="{{ $editURL }}" target="_blank" rel="noreferer">{{ $editThisPage }}</a>
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
{{/* Scroll To Top */}}
|
||||||
|
<button aria-hidden="true" id="backToTop" onClick="scrollUp();" class="transition-all transition duration-75 opacity-0 text-xs font-medium text-gray-500 hover:text-gray-900 dark:text-gray-400 dark:hover:text-gray-100 contrast-more:text-gray-800 contrast-more:dark:text-gray-50">
|
||||||
|
<span>
|
||||||
|
{{- $backToTop -}}
|
||||||
|
</span>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="inline ml-1 h-3.5 w-3.5 border rounded-full border-gray-500 hover:border-gray-900 dark:border-gray-400 dark:hover:border-gray-100 contrast-more:border-gray-800 contrast-more:dark:border-gray-50">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M4.5 15.75l7.5-7.5 7.5 7.5" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{ end -}}
|
{{ end -}}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
{{/* Split page raw content into fragments */}}
|
{{/* Split page raw content into fragments */}}
|
||||||
{{ $page := . }}
|
{{ $page := .context }}
|
||||||
|
{{ $type := .type | default "content" }}
|
||||||
|
|
||||||
{{ $headingKeys := slice }}
|
{{ $headingKeys := slice }}
|
||||||
{{ $headingTitles := slice }}
|
{{ $headingTitles := slice }}
|
||||||
@ -22,24 +23,40 @@
|
|||||||
{{ $len := len $headingKeys }}
|
{{ $len := len $headingKeys }}
|
||||||
{{ $data := dict }}
|
{{ $data := dict }}
|
||||||
|
|
||||||
{{ if eq $len 0 }}
|
{{ if eq $type "content" }}
|
||||||
{{ $data = $data | merge (dict "" $page.Plain) }}
|
{{/* Include full content of the page */}}
|
||||||
{{ else }}
|
{{ if eq $len 0 }}
|
||||||
{{ range seq $len }}
|
{{ $data = $data | merge (dict "" ($page.Plain | htmlUnescape | chomp)) }}
|
||||||
{{ $i := sub $len . }}
|
{{ else }}
|
||||||
{{ $headingKey := index $headingKeys $i }}
|
{{/* Split the raw content from bottom to top */}}
|
||||||
{{ $headingTitle := index $headingTitles $i }}
|
{{ range seq $len }}
|
||||||
|
{{ $i := sub $len . }}
|
||||||
|
{{ $headingKey := index $headingKeys $i }}
|
||||||
|
{{ $headingTitle := index $headingTitles $i }}
|
||||||
|
|
||||||
{{ if eq $i 0 }}
|
{{ if eq $i 0 }}
|
||||||
{{ $data = $data | merge (dict $headingKey ($content | markdownify | plainify)) }}
|
{{ $data = $data | merge (dict $headingKey ($content | markdownify | plainify | htmlUnescape | chomp)) }}
|
||||||
{{ else }}
|
{{ else }}
|
||||||
{{ $parts := split $content (printf "\n%s\n" $headingTitle) }}
|
{{ $parts := split $content (printf "\n%s\n" $headingTitle) }}
|
||||||
{{ $lastPart := index $parts (sub (len $parts) 1) }}
|
{{ $lastPart := index $parts (sub (len $parts) 1) }}
|
||||||
|
|
||||||
{{ $data = $data | merge (dict $headingKey ($lastPart | markdownify | plainify)) }}
|
{{ $data = $data | merge (dict $headingKey ($lastPart | markdownify | plainify | htmlUnescape | chomp)) }}
|
||||||
{{ $content = strings.TrimSuffix $lastPart $content }}
|
{{ $content = strings.TrimSuffix $lastPart $content }}
|
||||||
{{ $content = strings.TrimSuffix (printf "\n%s\n" $headingTitle) $content }}
|
{{ $content = strings.TrimSuffix (printf "\n%s\n" $headingTitle) $content }}
|
||||||
|
{{ end }}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
{{ else if (eq $type "heading" ) }}
|
||||||
|
{{/* Put heading keys with empty content to the data object */}}
|
||||||
|
{{ $data = dict "" "" }}
|
||||||
|
{{ range $headingKeys }}
|
||||||
|
{{ $data = $data | merge (dict . "") }}
|
||||||
|
{{ end }}
|
||||||
|
{{ else if (eq $type "title") }}
|
||||||
|
{{/* Use empty data object since title is included in search-data.json */}}
|
||||||
|
{{ $data = $data | merge (dict "" "") }}
|
||||||
|
{{ else if (eq $type "summary" ) }}
|
||||||
|
{{ $data = $data | merge (dict "" ($page.Summary | plainify | htmlUnescape | chomp)) }}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
||||||
{{ return $data }}
|
{{ return $data }}
|
||||||
|
@ -17,8 +17,8 @@
|
|||||||
<div class="overflow-x-auto mt-6 flex rounded-lg border py-2 ltr:pr-4 rtl:pl-4 contrast-more:border-current contrast-more:dark:border-current {{ $class }}">
|
<div class="overflow-x-auto mt-6 flex rounded-lg border py-2 ltr:pr-4 rtl:pl-4 contrast-more:border-current contrast-more:dark:border-current {{ $class }}">
|
||||||
<div class="select-none text-xl ltr:pl-3 ltr:pr-2 rtl:pr-3 rtl:pl-2" style='font-family: "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";'>{{ $emoji }}</div>
|
<div class="select-none text-xl ltr:pl-3 ltr:pr-2 rtl:pr-3 rtl:pl-2" style='font-family: "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";'>{{ $emoji }}</div>
|
||||||
<div class="w-full min-w-0 leading-7">
|
<div class="w-full min-w-0 leading-7">
|
||||||
<p class="mt-6 leading-7 first:mt-0">
|
<div class="mt-6 leading-7 first:mt-0">
|
||||||
{{ .Inner | markdownify }}
|
{{ .Inner | markdownify }}
|
||||||
</p>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -3,7 +3,8 @@
|
|||||||
"dev:theme": "hugo server --logLevel=debug --config=hugo.yaml,../dev.toml --environment=theme --source=exampleSite --themesDir=../.. --disableFastRender -D --port 1313",
|
"dev:theme": "hugo server --logLevel=debug --config=hugo.yaml,../dev.toml --environment=theme --source=exampleSite --themesDir=../.. --disableFastRender -D --port 1313",
|
||||||
"dev": "hugo server --source=exampleSite --themesDir=../.. --disableFastRender -D --port 1313",
|
"dev": "hugo server --source=exampleSite --themesDir=../.. --disableFastRender -D --port 1313",
|
||||||
"build:css": "npx postcss --config postcss.config.js --env production assets/css/styles.css -o assets/css/compiled/main.css",
|
"build:css": "npx postcss --config postcss.config.js --env production assets/css/styles.css -o assets/css/compiled/main.css",
|
||||||
"build": "hugo --gc --minify --themesDir=../.. --source=exampleSite"
|
"build": "hugo --gc --minify --themesDir=../.. --source=exampleSite",
|
||||||
|
"metrics": "hugo --themesDir=../.. --source=exampleSite --templateMetrics --templateMetricsHints"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tailwindcss/nesting": "^0.0.0-insiders.565cd3e",
|
"@tailwindcss/nesting": "^0.0.0-insiders.565cd3e",
|
||||||
|
@ -3,10 +3,10 @@ const colors = require('tailwindcss/colors')
|
|||||||
const makePrimaryColor =
|
const makePrimaryColor =
|
||||||
l =>
|
l =>
|
||||||
({ opacityValue }) => {
|
({ opacityValue }) => {
|
||||||
if (opacityValue === undefined) {
|
return (
|
||||||
return `hsl(var(--primary-hue) 100% ${l}%)`
|
`hsl(var(--primary-hue) var(--primary-saturation) ${l}%` +
|
||||||
}
|
(opacityValue ? ` / ${opacityValue})` : ')')
|
||||||
return `hsl(var(--primary-hue) 100% ${l}% / ${opacityValue})`
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @type {import('tailwindcss').Config} */
|
/** @type {import('tailwindcss').Config} */
|
||||||
|
Reference in New Issue
Block a user