Compare commits

..

15 Commits

Author SHA1 Message Date
Xin
9fc253dff5 chore: cache tree branch without leaf 2023-10-24 22:52:10 +01:00
Xin
0125822785 chore: move inline template to partial 2023-10-24 22:22:57 +01:00
Xin
1e1d1c8716 chore: add back mobile nav 2023-10-24 21:39:43 +01:00
Xin
1048ee47d7 fix: unescape html for link title 2023-10-24 20:41:50 +01:00
Xin
5842f893a3 chore: add toc in section tree json 2023-10-24 20:41:28 +01:00
Xin
78ce7c2f2e fix: link in sidebar extra component 2023-10-24 20:17:39 +01:00
Xin
0652772c15 refactor: pre-calculate section tree structure json 2023-10-24 00:17:48 +01:00
Xin
13e4eb3414 chore: add section-tree.html 2023-10-23 21:59:26 +01:00
Xin
529fcd8a62 chore: add metric command 2023-10-23 19:44:18 +01:00
Xin
21a13c49f9 chore: inline partial sidebar switches 2023-10-22 13:57:55 +01:00
Xin
98d0a3dc73 refactor: split out sidebar elements into partials 2023-10-22 11:17:26 +01:00
Xin
24f3178ea8 perf: cache scripts 2023-10-22 11:01:19 +01:00
Xin
230cc438b7 perf: cache sidebar footer 2023-10-21 23:22:45 +01:00
Xin
214cb7994f perf: cache sidebear-collapsible-button 2023-10-21 23:18:42 +01:00
Xin
792ad4b569 perf: cache partial "search.html" 2023-10-21 23:13:30 +01:00
86 changed files with 711 additions and 1304 deletions

View File

@ -3,7 +3,7 @@
"features": {
"ghcr.io/devcontainers/features/hugo:1": {
"extended": true,
"version": "0.119.0"
"version": "0.116.1"
},
"ghcr.io/devcontainers/features/node:1": {}
},

View File

@ -17,10 +17,10 @@ Demo → [imfing.github.io/hextra](https://imfing.github.io/hextra/)
## Features
- **Beautiful Design** - Inspired by Nextra, Hextra utilizes Tailwind CSS to offer a modern design that makes your site look outstanding.
- **Responsive Layout and Dark Mode** - It looks great on all devices, from mobile to desktop. Dark mode is also supported to accommodate various lighting conditions.
- **Fast and Lightweight** - Powered by Hugo, a lightning-fast static-site generator housed in a single binary file, Hextra keeps its footprint minimal. No JavaScript or Node.js are needed to use it.
- **Full-text Search** - Built-in offline full-text search powered by FlexSearch, no extra configuration required.
- **Battery-included** - Markdown, syntax highlighting, LaTeX math formulae, diagrams and Shortcodes elements to enhance your content. Table of contents, breadcrumbs, pagination, sidebar navigation and more are all automatically generated.
- **Responsive Layout and Dark Mode** - It looks great on all devices, from mobile, tablet to desktop. Dark mode is also supported to accomodate various lighting conditions.
- **Fast and Lightweight** - Powered by Hugo, a lightning-fast static-site generator housed in a single binary file, Hextra keeps its footprint minimal. No Javascript or Node.js are needed to use it.
- **Full-text Search** - Built-in offline full-text search powered by FlexSearch, no additional configuration required.
- **Battery-included** - Markdown, syntax highlighting, LaTeX math formulae, diagrams and Shortcodes elements to enhance your content. Table of contents, breadcumbs, pagination, sidebar navigation and more are all automatically generated.
- **Multi-language and SEO Ready** - Multi-language sites made easy with Hugo's multilingual mode. Out-of-the-box support is included for SEO tags, Open Graph, and Twitter Cards.
## Quick Start
@ -39,7 +39,7 @@ Refer to the [documentation](https://imfing.github.io/hextra/docs) for more info
## Contributing
Contributions are welcome.
Contributions are welcome!
Check out the [contributing guide](.github/CONTRIBUTING.md) to get started.
## License

View File

@ -499,9 +499,6 @@ video {
.pointer-events-none {
pointer-events: none;
}
.fixed {
position: fixed;
}
.absolute {
position: absolute;
}
@ -511,9 +508,6 @@ video {
.sticky {
position: sticky;
}
.inset-0 {
inset: 0px;
}
.inset-x-0 {
left: 0px;
right: 0px;
@ -549,9 +543,6 @@ video {
.top-full {
top: 100%;
}
.z-10 {
z-index: 10;
}
.z-20 {
z-index: 20;
}
@ -634,9 +625,6 @@ video {
.ml-4 {
margin-left: 1rem;
}
.mr-1 {
margin-right: 0.25rem;
}
.mr-2 {
margin-right: 0.5rem;
}
@ -851,9 +839,6 @@ video {
.flex-col {
flex-direction: column;
}
.flex-wrap {
flex-wrap: wrap;
}
.items-start {
align-items: flex-start;
}
@ -884,17 +869,6 @@ video {
.gap-4 {
gap: 1rem;
}
.gap-x-1 {
-moz-column-gap: 0.25rem;
column-gap: 0.25rem;
}
.gap-x-1\.5 {
-moz-column-gap: 0.375rem;
column-gap: 0.375rem;
}
.gap-y-2 {
row-gap: 0.5rem;
}
.overflow-auto {
overflow: auto;
}
@ -992,9 +966,6 @@ video {
--tw-border-opacity: 1;
border-color: rgb(254 249 195 / var(--tw-border-opacity));
}
.bg-black\/80 {
background-color: rgb(0 0 0 / 0.8);
}
.bg-black\/\[\.05\] {
background-color: rgb(0 0 0 / .05);
}
@ -1165,6 +1136,9 @@ video {
.pr-\[max\(env\(safe-area-inset-right\)\2c 1\.5rem\)\] {
padding-right: max(env(safe-area-inset-right),1.5rem);
}
.pt-1 {
padding-top: 0.25rem;
}
.pt-4 {
padding-top: 1rem;
}
@ -1183,9 +1157,6 @@ video {
.align-text-bottom {
vertical-align: text-bottom;
}
.align-\[-2\.5px\] {
vertical-align: -2.5px;
}
.font-mono {
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
}
@ -1415,6 +1386,9 @@ video {
.ease-in {
transition-timing-function: cubic-bezier(0.4, 0, 1, 1);
}
.ease-in-out {
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
}
.\[-webkit-tap-highlight-color\:transparent\] {
-webkit-tap-highlight-color: transparent;
}
@ -1428,13 +1402,13 @@ video {
-webkit-hyphens: auto;
hyphens: auto;
}
.\[transition\:background-color_1\.5s_ease\] {
transition: background-color 1.5s ease;
.\[text-underline-position\:from-font\] {
text-underline-position: from-font;
}
.\[word-break\:break-word\] {
word-break: break-word;
}
.content :where(h1):not(:where([class~=not-prose],[class~=not-prose] *)) {
.content h1 {
margin-top: 0.5rem;
font-size: 2.25rem;
font-weight: 700;
@ -1442,11 +1416,11 @@ video {
--tw-text-opacity: 1;
color: rgb(15 23 42 / var(--tw-text-opacity));
}
:is(html[class~="dark"] .content :where(h1):not(:where([class~=not-prose],[class~=not-prose] *))) {
:is(html[class~="dark"] .content h1) {
--tw-text-opacity: 1;
color: rgb(241 245 249 / var(--tw-text-opacity));
}
.content :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)) {
.content h2 {
margin-top: 2.5rem;
border-bottom-width: 1px;
border-color: rgb(229 229 229 / 0.7);
@ -1459,24 +1433,24 @@ video {
}
@media (prefers-contrast: more) {
.content :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)) {
.content h2 {
--tw-border-opacity: 1;
border-color: rgb(163 163 163 / var(--tw-border-opacity));
}
}
:is(html[class~="dark"] .content :where(h2):not(:where([class~=not-prose],[class~=not-prose] *))) {
:is(html[class~="dark"] .content h2) {
border-color: hsl(var(--primary-hue) var(--primary-saturation) 94% / 0.1);
--tw-text-opacity: 1;
color: rgb(241 245 249 / var(--tw-text-opacity));
}
@media (prefers-contrast: more) {
:is(html[class~="dark"] .content :where(h2):not(:where([class~=not-prose],[class~=not-prose] *))) {
:is(html[class~="dark"] .content h2) {
--tw-border-opacity: 1;
border-color: rgb(163 163 163 / var(--tw-border-opacity));
}
}
.content :where(h3):not(:where([class~=not-prose],[class~=not-prose] *)) {
.content h3 {
margin-top: 2rem;
font-size: 1.5rem;
font-weight: 600;
@ -1484,11 +1458,11 @@ video {
--tw-text-opacity: 1;
color: rgb(15 23 42 / var(--tw-text-opacity));
}
:is(html[class~="dark"] .content :where(h3):not(:where([class~=not-prose],[class~=not-prose] *))) {
:is(html[class~="dark"] .content h3) {
--tw-text-opacity: 1;
color: rgb(241 245 249 / var(--tw-text-opacity));
}
.content :where(h4):not(:where([class~=not-prose],[class~=not-prose] *)) {
.content h4 {
margin-top: 2rem;
font-size: 1.25rem;
font-weight: 600;
@ -1496,11 +1470,11 @@ video {
--tw-text-opacity: 1;
color: rgb(15 23 42 / var(--tw-text-opacity));
}
:is(html[class~="dark"] .content :where(h4):not(:where([class~=not-prose],[class~=not-prose] *))) {
:is(html[class~="dark"] .content h4) {
--tw-text-opacity: 1;
color: rgb(241 245 249 / var(--tw-text-opacity));
}
.content :where(h5):not(:where([class~=not-prose],[class~=not-prose] *)) {
.content h5 {
margin-top: 2rem;
font-size: 1.125rem;
font-weight: 600;
@ -1508,11 +1482,11 @@ video {
--tw-text-opacity: 1;
color: rgb(15 23 42 / var(--tw-text-opacity));
}
:is(html[class~="dark"] .content :where(h5):not(:where([class~=not-prose],[class~=not-prose] *))) {
:is(html[class~="dark"] .content h5) {
--tw-text-opacity: 1;
color: rgb(241 245 249 / var(--tw-text-opacity));
}
.content :where(h6):not(:where([class~=not-prose],[class~=not-prose] *)) {
.content h6 {
margin-top: 2rem;
font-size: 1rem;
font-weight: 600;
@ -1520,25 +1494,33 @@ video {
--tw-text-opacity: 1;
color: rgb(15 23 42 / var(--tw-text-opacity));
}
:is(html[class~="dark"] .content :where(h6):not(:where([class~=not-prose],[class~=not-prose] *))) {
:is(html[class~="dark"] .content h6) {
--tw-text-opacity: 1;
color: rgb(241 245 249 / var(--tw-text-opacity));
}
.content :where(p):not(:where([class~=not-prose],[class~=not-prose] *)) {
.content p {
margin-top: 1.5rem;
line-height: 1.75rem;
}
.content :where(p):not(:where([class~=not-prose],[class~=not-prose] *)):first-child {
.content p:first-child {
margin-top: 0px;
}
.content :where(a):not(:where([class~=not-prose],[class~=not-prose] *)) {
.content .not-prose p {
margin-top: 0px;
line-height: 1.5;
}
.content a {
--tw-text-opacity: 1;
color: hsl(var(--primary-hue) var(--primary-saturation) 45% / var(--tw-text-opacity));
text-decoration-line: underline;
text-decoration-thickness: from-font;
text-underline-position: from-font;
}
.content :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)) {
.content .not-prose a {
color: currentColor;
text-decoration-line: none;
}
.content blockquote {
margin-top: 1.5rem;
--tw-border-opacity: 1;
border-color: rgb(209 213 219 / var(--tw-border-opacity));
@ -1546,24 +1528,24 @@ video {
--tw-text-opacity: 1;
color: rgb(55 65 81 / var(--tw-text-opacity));
}
.content :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)):first-child {
.content blockquote:first-child {
margin-top: 0px;
}
:is([dir="ltr"] .content :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *))) {
:is([dir="ltr"] .content blockquote) {
border-left-width: 2px;
padding-left: 1.5rem;
}
:is([dir="rtl"] .content :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *))) {
:is([dir="rtl"] .content blockquote) {
border-right-width: 2px;
padding-right: 1.5rem;
}
:is(html[class~="dark"] .content :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *))) {
:is(html[class~="dark"] .content blockquote) {
--tw-border-opacity: 1;
border-color: rgb(55 65 81 / var(--tw-border-opacity));
--tw-text-opacity: 1;
color: rgb(156 163 175 / var(--tw-text-opacity));
}
.content :where(pre):not(:where(.code-block pre, [class~=not-prose],[class~=not-prose] *)) {
.content pre:not(.code-block pre) {
margin-bottom: 1rem;
overflow-x: auto;
border-radius: 0.75rem;
@ -1577,23 +1559,23 @@ video {
}
@media (prefers-contrast: more) {
.content :where(pre):not(:where(.code-block pre, [class~=not-prose],[class~=not-prose] *)) {
.content pre:not(.code-block pre) {
border-width: 1px;
border-color: hsl(var(--primary-hue) var(--primary-saturation) 24% / 0.2);
--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);
}
}
:is(html[class~="dark"] .content :where(pre):not(:where(.code-block pre, [class~=not-prose],[class~=not-prose] *))) {
:is(html[class~="dark"] .content pre:not(.code-block pre)) {
background-color: hsl(var(--primary-hue) var(--primary-saturation) 77% / 0.1);
}
@media (prefers-contrast: more) {
:is(html[class~="dark"] .content :where(pre):not(:where(.code-block pre, [class~=not-prose],[class~=not-prose] *))) {
:is(html[class~="dark"] .content pre:not(.code-block pre)) {
border-color: hsl(var(--primary-hue) var(--primary-saturation) 94% / 0.4);
}
}
.content :where(code):not(:where(.code-block code, [class~=not-prose],[class~=not-prose] *)) {
.content code:not(.code-block code) {
overflow-wrap: break-word;
border-radius: 0.375rem;
border-width: 1px;
@ -1607,38 +1589,38 @@ video {
padding-right: .25em;
font-size: .9em;
}
:is(html[class~="dark"] .content :where(code):not(:where(.code-block code, [class~=not-prose],[class~=not-prose] *))) {
:is(html[class~="dark"] .content code:not(.code-block code)) {
border-color: rgb(255 255 255 / 0.1);
background-color: rgb(255 255 255 / 0.1);
}
.content :where(table):not(:where(.code-block table, [class~=not-prose],[class~=not-prose] *)) {
.content table:not(.code-block table) {
margin-top: 1.5rem;
display: block;
overflow-x: auto;
padding: 0px;
}
.content :where(table):not(:where(.code-block table, [class~=not-prose],[class~=not-prose] *)):first-child {
.content table:not(.code-block table):first-child {
margin-top: 0px;
}
.content :where(table):not(:where(.code-block table, [class~=not-prose],[class~=not-prose] *)) tr {
.content table:not(.code-block table) tr {
margin: 0px;
border-top-width: 1px;
--tw-border-opacity: 1;
border-color: rgb(209 213 219 / var(--tw-border-opacity));
padding: 0px;
}
.content :where(table):not(:where(.code-block table, [class~=not-prose],[class~=not-prose] *)) tr:nth-child(even) {
.content table:not(.code-block table) tr:nth-child(even) {
--tw-bg-opacity: 1;
background-color: rgb(243 244 246 / var(--tw-bg-opacity));
}
:is(html[class~="dark"] .content :where(table):not(:where(.code-block table, [class~=not-prose],[class~=not-prose] *)) tr) {
:is(html[class~="dark"] .content table:not(.code-block table) tr) {
--tw-border-opacity: 1;
border-color: rgb(75 85 99 / var(--tw-border-opacity));
}
:is(html[class~="dark"] .content :where(table):not(:where(.code-block table, [class~=not-prose],[class~=not-prose] *)) tr):nth-child(even) {
:is(html[class~="dark"] .content table:not(.code-block table) tr):nth-child(even) {
background-color: rgb(75 85 99 / 0.2);
}
.content :where(table):not(:where(.code-block table, [class~=not-prose],[class~=not-prose] *)) th {
.content table:not(.code-block table) th {
margin: 0px;
border-width: 1px;
--tw-border-opacity: 1;
@ -1649,11 +1631,11 @@ video {
padding-bottom: 0.5rem;
font-weight: 600;
}
:is(html[class~="dark"] .content :where(table):not(:where(.code-block table, [class~=not-prose],[class~=not-prose] *)) th) {
:is(html[class~="dark"] .content table:not(.code-block table) th) {
--tw-border-opacity: 1;
border-color: rgb(75 85 99 / var(--tw-border-opacity));
}
.content :where(table):not(:where(.code-block table, [class~=not-prose],[class~=not-prose] *)) td {
.content table:not(.code-block table) td {
margin: 0px;
border-width: 1px;
--tw-border-opacity: 1;
@ -1663,45 +1645,52 @@ video {
padding-top: 0.5rem;
padding-bottom: 0.5rem;
}
:is(html[class~="dark"] .content :where(table):not(:where(.code-block table, [class~=not-prose],[class~=not-prose] *)) td) {
:is(html[class~="dark"] .content table:not(.code-block table) td) {
--tw-border-opacity: 1;
border-color: rgb(75 85 99 / var(--tw-border-opacity));
}
.content :where(ol):not(:where([class~=not-prose],[class~=not-prose] *)) {
.content ol {
margin-top: 1.5rem;
list-style-type: decimal;
}
.content :where(ol):not(:where([class~=not-prose],[class~=not-prose] *)):first-child {
.content ol:first-child {
margin-top: 0px;
}
:is([dir="ltr"] .content :where(ol):not(:where([class~=not-prose],[class~=not-prose] *))) {
:is([dir="ltr"] .content ol) {
margin-left: 1.5rem;
}
:is([dir="rtl"] .content :where(ol):not(:where([class~=not-prose],[class~=not-prose] *))) {
:is([dir="rtl"] .content ol) {
margin-right: 1.5rem;
}
.content :where(ol):not(:where([class~=not-prose],[class~=not-prose] *)) li {
.content ol li {
margin-top: 0.5rem;
margin-bottom: 0.5rem;
}
.content :where(ul):not(:where([class~=not-prose],[class~=not-prose] *)) {
.content ul {
margin-top: 1.5rem;
list-style-type: disc;
}
.content :where(ul):not(:where([class~=not-prose],[class~=not-prose] *)):first-child {
.content ul:first-child {
margin-top: 0px;
}
:is([dir="ltr"] .content :where(ul):not(:where([class~=not-prose],[class~=not-prose] *))) {
:is([dir="ltr"] .content ul) {
margin-left: 1.5rem;
}
:is([dir="rtl"] .content :where(ul):not(:where([class~=not-prose],[class~=not-prose] *))) {
:is([dir="rtl"] .content ul) {
margin-right: 1.5rem;
}
.content :where(ul):not(:where([class~=not-prose],[class~=not-prose] *)) li {
.content ul li {
margin-top: 0.5rem;
margin-bottom: 0.5rem;
}
.content :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)) {
.content .not-prose ul, .content .not-prose ol {
margin: 0px;
list-style-type: none;
}
.content .not-prose ul li, .content .not-prose ol li {
margin: 0px;
}
.content kbd {
overflow-wrap: break-word;
border-radius: 0.375rem;
border-width: 1px;
@ -1715,25 +1704,29 @@ video {
padding-right: .25em;
font-size: .9em;
}
:is(html[class~="dark"] .content :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *))) {
:is(html[class~="dark"] .content kbd) {
border-color: rgb(255 255 255 / 0.1);
background-color: rgb(255 255 255 / 0.1);
}
.content :where(pre.mermaid):not(:where(.code-block pre, [class~=not-prose],[class~=not-prose] *)) {
.content pre:not(.code-block pre).mermaid {
border-radius: 0px;
background-color: transparent;
}
:is(html[class~="dark"] .content :where(pre.mermaid):not(:where(.code-block pre, [class~=not-prose],[class~=not-prose] *))) {
:is(html[class~="dark"] .content pre:not(.code-block pre).mermaid) {
background-color: transparent;
}
.content :where(img):not(:where([class~=not-prose],[class~=not-prose] *)) {
.content img {
margin-left: auto;
margin-right: auto;
margin-top: 1rem;
margin-bottom: 1rem;
border-radius: 0.375rem;
}
.content :where(figure):not(:where([class~=not-prose],[class~=not-prose] *)) figcaption {
.content .not-prose img {
margin: 0px;
border-radius: 0px;
}
.content figure figcaption {
margin-top: 0.5rem;
display: block;
text-align: center;
@ -1741,7 +1734,7 @@ video {
--tw-text-opacity: 1;
color: rgb(107 114 128 / var(--tw-text-opacity));
}
:is(html[class~="dark"] .content :where(figure):not(:where([class~=not-prose],[class~=not-prose] *)) figcaption) {
:is(html[class~="dark"] .content figure figcaption) {
--tw-text-opacity: 1;
color: rgb(156 163 175 / var(--tw-text-opacity));
}
@ -1790,6 +1783,50 @@ span:target + .subheading-anchor:after {
--tw-text-opacity: 1;
color: rgb(115 115 115 / var(--tw-text-opacity));
}
article.typesetting-article {
font-size: 17px;
font-feature-settings:
'rlig' 1,
'calt' 1;
}
article.typesetting-article h1 {
margin-top: 1.5rem;
margin-bottom: 1rem;
text-align: center;
font-size: 2.5rem;
}
article.typesetting-article h2 {
border-style: none;
}
article.typesetting-article a {
text-decoration-line: none;
}
article.typesetting-article a:hover {
text-decoration-line: underline;
}
article.typesetting-article p {
line-height: 2rem;
}
article.typesetting-article code {
border-style: none;
}
:is(html[class~="dark"] article.typesetting-article code) {
--tw-bg-opacity: 1;
background-color: rgb(64 64 64 / var(--tw-bg-opacity));
}
:is(html[class~="dark"] article.typesetting-article pre code) {
background-color: transparent;
}
article.typesetting-article .subheading-anchor + a {
text-decoration-line: none;
}
article.typesetting-article .subheading-anchor + a::after {
content: var(--tw-content);
display: none;
}
article.typesetting-article .subheading-anchor + a:hover {
text-decoration-line: none;
}
article details > summary::-webkit-details-marker {
display: none;
}
@ -2204,7 +2241,7 @@ article details > summary::before {
}
.chroma .ln,
.chroma .lnt:not(.hl > .lnt),
.chroma .hl:not(.line) {
.chroma .hl {
min-width: 2.6rem;
padding-left: 1rem;
padding-right: 1rem;
@ -2213,7 +2250,7 @@ article details > summary::before {
}
:is(html[class~="dark"] .chroma .ln),:is(html[class~="dark"]
.chroma .lnt:not(.hl > .lnt)),:is(html[class~="dark"]
.chroma .hl:not(.line)) {
.chroma .hl) {
--tw-text-opacity: 1;
color: rgb(212 212 212 / var(--tw-text-opacity));
}
@ -2443,7 +2480,6 @@ article details > summary::before {
}
.sidebar-container li.open > div {
height: auto;
padding-top: 0.25rem;
}
.sidebar-container li.open > a > span > svg > path {
--tw-rotate: 90deg;
@ -2533,19 +2569,6 @@ nav .search-wrapper {
--tw-shadow-color: rgb(115 115 115 / 0.4);
--tw-shadow: var(--tw-shadow-colored);
}
@supports (
((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px)))
) {
.code-copy-btn {
--tw-bg-opacity: .85;
--tw-backdrop-blur: blur(12px);
-webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);
backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);
}
:is(html[class~="dark"] .code-copy-btn) {
--tw-bg-opacity: 0.8;
}
}
html {
font-size: 1rem;
-webkit-font-smoothing: antialiased;
@ -2752,9 +2775,6 @@ body {
--tw-rotate: 90deg;
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
}
.group:hover .group-hover\:underline {
text-decoration-line: underline;
}
.group\/code:hover .group-hover\/code\:opacity-100 {
opacity: 1;
}
@ -3025,9 +3045,6 @@ body {
:is(html[class~="dark"] .dark\:border-yellow-200\/30) {
border-color: rgb(254 240 138 / 0.3);
}
:is(html[class~="dark"] .dark\:bg-black\/60) {
background-color: rgb(0 0 0 / 0.6);
}
:is(html[class~="dark"] .dark\:bg-blue-900\/30) {
background-color: rgb(30 58 138 / 0.3);
}

View File

@ -1,7 +0,0 @@
@supports (
(-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))
) {
.code-copy-btn {
@apply backdrop-blur-md bg-opacity-[.85] dark:bg-opacity-80;
}
}

View File

@ -13,7 +13,7 @@
@apply h-0;
}
li.open > div {
@apply h-auto pt-1;
@apply h-auto;
}
li.open > a > span > svg > path {
@apply rotate-90;

View File

@ -32,7 +32,7 @@
}
.ln,
.lnt:not(.hl > .lnt),
.hl:not(.line) {
.hl {
@apply pl-4 pr-4 min-w-[2.6rem] text-neutral-600 dark:text-neutral-300;
}
.lntd {

View File

@ -8,7 +8,6 @@
@import "components/sidebar.css";
@import "components/navbar.css";
@import "components/scrollbar.css";
@import "components/code-copy.css";
html {
@apply text-base antialiased;

View File

@ -1,38 +1,44 @@
.content {
:where(h1):not(:where([class~=not-prose],[class~=not-prose] *)) {
h1 {
@apply mt-2 text-4xl font-bold tracking-tight text-slate-900 dark:text-slate-100;
}
:where(h2):not(:where([class~=not-prose],[class~=not-prose] *)) {
h2 {
@apply font-semibold tracking-tight text-slate-900 dark:text-slate-100 mt-10 border-b pb-1 text-3xl border-neutral-200/70 contrast-more:border-neutral-400 dark:border-primary-100/10 contrast-more:dark:border-neutral-400;
}
:where(h3):not(:where([class~=not-prose],[class~=not-prose] *)) {
h3 {
@apply font-semibold tracking-tight text-slate-900 dark:text-slate-100 mt-8 text-2xl;
}
:where(h4):not(:where([class~=not-prose],[class~=not-prose] *)) {
h4 {
@apply font-semibold tracking-tight text-slate-900 dark:text-slate-100 mt-8 text-xl;
}
:where(h5):not(:where([class~=not-prose],[class~=not-prose] *)) {
h5 {
@apply font-semibold tracking-tight text-slate-900 dark:text-slate-100 mt-8 text-lg;
}
:where(h6):not(:where([class~=not-prose],[class~=not-prose] *)) {
h6 {
@apply font-semibold tracking-tight text-slate-900 dark:text-slate-100 mt-8 text-base;
}
:where(p):not(:where([class~=not-prose],[class~=not-prose] *)) {
p {
@apply mt-6 leading-7 first:mt-0;
}
:where(a):not(:where([class~=not-prose],[class~=not-prose] *)) {
.not-prose p {
@apply mt-0 leading-normal;
}
a {
@apply text-primary-600 underline decoration-from-font [text-underline-position:from-font];
}
:where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)) {
.not-prose a {
@apply text-current no-underline;
}
blockquote {
@apply mt-6 border-gray-300 italic text-gray-700 dark:border-gray-700 dark:text-gray-400 first:mt-0 ltr:border-l-2 ltr:pl-6 rtl:border-r-2 rtl:pr-6;
}
:where(pre):not(:where(.code-block pre, [class~=not-prose],[class~=not-prose] *)) {
pre:not(.code-block pre) {
@apply bg-primary-700/5 mb-4 overflow-x-auto rounded-xl font-medium subpixel-antialiased dark:bg-primary-300/10 text-[.9em] contrast-more:border contrast-more:border-primary-900/20 contrast-more:contrast-150 contrast-more:dark:border-primary-100/40 py-4;
}
:where(code):not(:where(.code-block code, [class~=not-prose],[class~=not-prose] *)) {
code:not(.code-block code) {
@apply border-black border-opacity-[0.04] bg-opacity-[0.03] bg-black break-words rounded-md border py-0.5 px-[.25em] text-[.9em] dark:border-white/10 dark:bg-white/10;
}
:where(table):not(:where(.code-block table, [class~=not-prose],[class~=not-prose] *)) {
table:not(.code-block table) {
@apply block overflow-x-auto mt-6 p-0 first:mt-0;
tr {
@ -45,28 +51,37 @@
@apply m-0 border border-gray-300 px-4 py-2 dark:border-gray-600;
}
}
:where(ol):not(:where([class~=not-prose],[class~=not-prose] *)) {
ol {
@apply mt-6 list-decimal first:mt-0 ltr:ml-6 rtl:mr-6;
li {
@apply my-2;
}
}
:where(ul):not(:where([class~=not-prose],[class~=not-prose] *)) {
ul {
@apply mt-6 list-disc first:mt-0 ltr:ml-6 rtl:mr-6;
li {
@apply my-2;
}
}
:where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)) {
.not-prose ul, .not-prose ol {
@apply m-0 list-none;
li {
@apply m-0;
}
}
kbd {
@apply border-black border-opacity-[0.04] bg-opacity-[0.03] bg-black break-words rounded-md border py-0.5 px-[.25em] text-[.9em] dark:border-white/10 dark:bg-white/10;
}
:where(pre.mermaid):not(:where(.code-block pre, [class~=not-prose],[class~=not-prose] *)) {
pre:not(.code-block pre).mermaid {
@apply bg-transparent rounded-none dark:bg-transparent;
}
:where(img):not(:where([class~=not-prose],[class~=not-prose] *)) {
img {
@apply mx-auto my-4 rounded-md;
}
:where(figure):not(:where([class~=not-prose],[class~=not-prose] *)) {
.not-prose img {
@apply m-0 rounded-none;
}
figure {
figcaption {
@apply text-sm text-gray-500 dark:text-gray-400 mt-2 block text-center;
}
@ -100,6 +115,35 @@
}
}
article.typesetting-article {
font-size: 17px;
font-feature-settings:
'rlig' 1,
'calt' 1;
h1 {
@apply mt-6 mb-4 text-center;
font-size: 2.5rem;
}
h2 {
@apply border-none;
}
a {
@apply no-underline hover:underline;
}
p {
@apply leading-8;
}
code {
@apply border-none dark:bg-neutral-700;
}
pre code {
@apply dark:bg-transparent;
}
.subheading-anchor + a {
@apply no-underline hover:no-underline after:hidden;
}
}
article details > summary {
&::-webkit-details-marker {
@apply hidden;

View File

@ -33,8 +33,8 @@ document.addEventListener('DOMContentLoaded', function () {
// Add click event listener for copy button
button.addEventListener('click', function (e) {
e.preventDefault();
// Get the code target
const target = button.parentElement.previousElementSibling;
const targetId = button.getAttribute('data-clipboard-target');
const target = document.querySelector(targetId);
let codeElement;
if (target.tagName === 'CODE') {
codeElement = target;
@ -44,17 +44,14 @@ document.addEventListener('DOMContentLoaded', function () {
codeElement = codeElements[codeElements.length - 1];
}
if (codeElement) {
let code = codeElement.innerText;
// Replace double newlines with single newlines in the innerText
// as each line inside <span> has trailing newline '\n'
if ("lang" in codeElement.dataset) {
code = code.replace(/\n\n/g, '\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');
}, 1000);
}, 500);
}).catch(function (err) {
console.error('Failed to copy text: ', err);
});

View File

@ -1,49 +1,19 @@
// Hamburger menu for mobile navigation
document.addEventListener('DOMContentLoaded', function () {
const menu = document.querySelector('.hamburger-menu');
const overlay = document.querySelector('.mobile-menu-overlay');
const menu = document.querySelector('.hamburger-menu');
menu.addEventListener('click', (e) => {
e.preventDefault();
const sidebarContainer = document.querySelector('.sidebar-container');
// Initialize the overlay
const overlayClasses = ['fixed', 'inset-0', 'z-10', 'bg-black/80', 'dark:bg-black/60'];
overlay.classList.add('bg-transparent');
overlay.classList.remove("hidden", ...overlayClasses);
// Toggle the hamburger menu
menu.querySelector('svg').classList.toggle('open');
function toggleMenu() {
// Toggle the hamburger menu
menu.querySelector('svg').classList.toggle('open');
// When the menu is open, we want to show the navigation sidebar
sidebarContainer.classList.toggle('max-md:[transform:translate3d(0,-100%,0)]');
sidebarContainer.classList.toggle('max-md:[transform:translate3d(0,0,0)]');
// When the menu is open, we want to show the navigation sidebar
sidebarContainer.classList.toggle('max-md:[transform:translate3d(0,-100%,0)]');
sidebarContainer.classList.toggle('max-md:[transform:translate3d(0,0,0)]');
// When the menu is open, we want to prevent the body from scrolling
document.body.classList.toggle('overflow-hidden');
document.body.classList.toggle('md:overflow-auto');
}
menu.addEventListener('click', (e) => {
e.preventDefault();
toggleMenu();
if (overlay.classList.contains('bg-transparent')) {
// Show the overlay
overlay.classList.add(...overlayClasses);
overlay.classList.remove('bg-transparent');
} else {
// Hide the overlay
overlay.classList.remove(...overlayClasses);
overlay.classList.add('bg-transparent');
}
});
overlay.addEventListener('click', (e) => {
e.preventDefault();
toggleMenu();
// Hide the overlay
overlay.classList.remove(...overlayClasses);
overlay.classList.add('bg-transparent');
});
// When the menu is open, we want to prevent the body from scrolling
document.body.classList.toggle('overflow-hidden');
document.body.classList.toggle('md:overflow-auto');
});

View File

@ -9,11 +9,6 @@ github: >
<path d="M12 3C7.0275 3 3 7.12937 3 12.2276C3 16.3109 5.57625 19.7597 9.15374 20.9824C9.60374 21.0631 9.77249 20.7863 9.77249 20.5441C9.77249 20.3249 9.76125 19.5982 9.76125 18.8254C7.5 19.2522 6.915 18.2602 6.735 17.7412C6.63375 17.4759 6.19499 16.6569 5.8125 16.4378C5.4975 16.2647 5.0475 15.838 5.80124 15.8264C6.51 15.8149 7.01625 16.4954 7.18499 16.7723C7.99499 18.1679 9.28875 17.7758 9.80625 17.5335C9.885 16.9337 10.1212 16.53 10.38 16.2993C8.3775 16.0687 6.285 15.2728 6.285 11.7432C6.285 10.7397 6.63375 9.9092 7.20749 9.26326C7.1175 9.03257 6.8025 8.08674 7.2975 6.81794C7.2975 6.81794 8.05125 6.57571 9.77249 7.76377C10.4925 7.55615 11.2575 7.45234 12.0225 7.45234C12.7875 7.45234 13.5525 7.55615 14.2725 7.76377C15.9937 6.56418 16.7475 6.81794 16.7475 6.81794C17.2424 8.08674 16.9275 9.03257 16.8375 9.26326C17.4113 9.9092 17.76 10.7281 17.76 11.7432C17.76 15.2843 15.6563 16.0687 13.6537 16.2993C13.98 16.5877 14.2613 17.1414 14.2613 18.0065C14.2613 19.2407 14.25 20.2326 14.25 20.5441C14.25 20.7863 14.4188 21.0746 14.8688 20.9824C16.6554 20.364 18.2079 19.1866 19.3078 17.6162C20.4077 16.0457 20.9995 14.1611 21 12.2276C21 7.12937 16.9725 3 12 3Z"></path>
</svg>
codeberg: >
<svg fill="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="M11.955.49A12 12 0 0 0 0 12.49a12 12 0 0 0 1.832 6.373L11.838 5.928a.187.14 0 0 1 .324 0l10.006 12.935A12 12 0 0 0 24 12.49a12 12 0 0 0-12-12 12 12 0 0 0-.045 0zm.375 6.467 4.416 16.553a12 12 0 0 0 5.137-4.213z"/>
</svg>
hextra: <svg viewBox="0 0 180 180" xmlns="http://www.w3.org/2000/svg" fill="currentColor"><path fill-rule="evenodd" clip-rule="evenodd" d="m 105.50024,22.224647 c -9.59169,-5.537563 -21.40871,-5.537563 -31.000093,0 L 39.054693,42.689119 C 29.463353,48.226675 23.55484,58.460531 23.55484,69.535642 v 40.928918 c 0,11.07542 5.908513,21.3092 15.499853,26.84652 l 35.445453,20.46446 c 9.591313,5.53732 21.408404,5.53732 31.000094,0 l 35.44507,-20.46446 c 9.59131,-5.53732 15.49985,-15.7711 15.49985,-26.84652 V 69.535642 c 0,-11.075111 -5.90854,-21.308967 -15.49985,-26.846523 z M 34.112797,85.737639 c -1.384445,2.397827 -1.384445,5.352099 0,7.749927 l 24.781554,42.922974 c 1.38437,2.39783 3.942853,3.87496 6.711592,3.87496 h 49.563107 c 2.76905,0 5.3273,-1.47713 6.71144,-3.87496 l 24.78194,-42.922974 c 1.38414,-2.397828 1.38414,-5.3521 0,-7.749927 L 121.88049,42.814746 c -1.38414,-2.397828 -3.94239,-3.874964 -6.71144,-3.874964 H 65.605944 c -2.768739,0 -5.327223,1.477059 -6.711592,3.874964 z" style="stroke-width:0.774993" /></svg>
hugo: <svg viewBox="0 0 370 391" xmlns="http://www.w3.org/2000/svg"><g clip-rule="evenodd" fill-rule="evenodd"><path d="m207.5 22.4 114.4 66.6c13.5 7.9 21.9 22.4 21.9 38v136.4c0 17.3-9.3 33.3-24.5 41.8l-113.5 63.9a49.06 49.06 0 0 1 -48.5-.2l-104.5-60.1c-16.4-9.5-26.6-27-26.6-45.9v-129.5c0-19.1 9.9-36.8 26.1-46.8l102.8-63.5c16-9.9 36.2-10.1 52.4-.7z" fill="#ff4088" stroke="#c9177e" stroke-width="27" /><path d="m105.6 298.2v-207.2h43.4v75.5h71.9v-75.5h43.5v207.2h-43.5v-90.6h-71.9v90.6z" fill="#fff" /></g></svg>
@ -275,4 +270,3 @@ twitter: <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill=
mastodon: <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="currentColor" d="M23.268 5.313c-.35-2.578-2.617-4.61-5.304-5.004C17.51.242 15.792 0 11.813 0h-.03c-3.98 0-4.835.242-5.288.309C3.882.692 1.496 2.518.917 5.127.64 6.412.61 7.837.661 9.143c.074 1.874.088 3.745.26 5.611.118 1.24.325 2.47.62 3.68.55 2.237 2.777 4.098 4.96 4.857 2.336.792 4.849.923 7.256.38.265-.061.527-.132.786-.213.585-.184 1.27-.39 1.774-.753a.057.057 0 0 0 .023-.043v-1.809a.052.052 0 0 0-.02-.041.053.053 0 0 0-.046-.01 20.282 20.282 0 0 1-4.709.545c-2.73 0-3.463-1.284-3.674-1.818a5.593 5.593 0 0 1-.319-1.433.053.053 0 0 1 .066-.054c1.517.363 3.072.546 4.632.546.376 0 .75 0 1.125-.01 1.57-.044 3.224-.124 4.768-.422.038-.008.077-.015.11-.024 2.435-.464 4.753-1.92 4.989-5.604.008-.145.03-1.52.03-1.67.002-.512.167-3.63-.024-5.545zm-3.748 9.195h-2.561V8.29c0-1.309-.55-1.976-1.67-1.976-1.23 0-1.846.79-1.846 2.35v3.403h-2.546V8.663c0-1.56-.617-2.35-1.848-2.35-1.112 0-1.668.668-1.67 1.977v6.218H4.822V8.102c0-1.31.337-2.35 1.011-3.12.696-.77 1.608-1.164 2.74-1.164 1.311 0 2.302.5 2.962 1.498l.638 1.06.638-1.06c.66-.999 1.65-1.498 2.96-1.498 1.13 0 2.043.395 2.74 1.164.675.77 1.012 1.81 1.012 3.12z"></path></svg>
youtube: <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill="currentColor" d="M8.051 1.999h.089c.822.003 4.987.033 6.11.335a2.01 2.01 0 0 1 1.415 1.42c.101.38.172.883.22 1.402l.01.104l.022.26l.008.104c.065.914.073 1.77.074 1.957v.075c-.001.194-.01 1.108-.082 2.06l-.008.105l-.009.104c-.05.572-.124 1.14-.235 1.558a2.007 2.007 0 0 1-1.415 1.42c-1.16.312-5.569.334-6.18.335h-.142c-.309 0-1.587-.006-2.927-.052l-.17-.006l-.087-.004l-.171-.007l-.171-.007c-1.11-.049-2.167-.128-2.654-.26a2.007 2.007 0 0 1-1.415-1.419c-.111-.417-.185-.986-.235-1.558L.09 9.82l-.008-.104A31.4 31.4 0 0 1 0 7.68v-.123c.002-.215.01-.958.064-1.778l.007-.103l.003-.052l.008-.104l.022-.26l.01-.104c.048-.519.119-1.023.22-1.402a2.007 2.007 0 0 1 1.415-1.42c.487-.13 1.544-.21 2.654-.26l.17-.007l.172-.006l.086-.003l.171-.007A99.788 99.788 0 0 1 7.858 2h.193zM6.4 5.209v4.818l4.157-2.408L6.4 5.209z"/></svg>
x-twitter: <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M389.2 48h70.6L305.6 224.2 487 464H345L233.7 318.6 106.5 464H35.8L200.7 275.5 26.8 48H172.4L272.9 180.9 389.2 48zM364.4 421.8h39.1L151.1 88h-42L364.4 421.8z"/></svg>
linkedin: <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="currentColor" d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037c-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85c3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433a2.062 2.062 0 0 1-2.063-2.065a2.064 2.064 0 1 1 2.063 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"/></svg>

View File

@ -57,7 +57,7 @@ layout: hextra-home
subtitle="No dependency or Node.js is needed to use Hextra. Powered by Hugo, one of *the fastest* static site generators, building your site in just seconds with a single binary."
>}}
{{< hextra/feature-card
title="Responsive with Dark Mode Included"
title="Reponsive with Dark Mode Included"
subtitle="Looks great on different screen sizes. Built-in dark mode support, with auto-switching based on user's system preference."
>}}
{{< hextra/feature-card

View File

@ -1,76 +0,0 @@
---
title: Hextra 主题
layout: hextra-home
---
{{< hextra/hero-badge >}}
<div class="w-2 h-2 rounded-full bg-primary-400"></div>
<span>免费 开源</span>
{{< icon name="arrow-circle-right" attributes="height=14" >}}
{{< /hextra/hero-badge >}}
<div class="mt-6 mb-6">
{{< hextra/hero-headline >}}
创建现代化网站&nbsp;<br class="sm:block hidden" />由 Markdown 和 Hugo 驱动
{{< /hextra/hero-headline >}}
</div>
<div class="mb-12">
{{< hextra/hero-subtitle >}}
极速且全能的 Hugo 主题框架&nbsp;<br class="sm:block hidden" />为构建现代化的静态网站而生
{{< /hextra/hero-subtitle >}}
</div>
<div class="mb-6">
{{< hextra/hero-button text="现在开始" link="docs" >}}
</div>
<div class="mt-6"></div>
{{< hextra/feature-grid >}}
{{< hextra/feature-card
title="快速且功能全面"
subtitle="简单易用,功能强大丰富。"
class="aspect-auto md:aspect-[1.1/1] max-md:min-h-[340px]"
image="/images/hextra-doc.webp"
imageClass="top-[40%] left-[24px] w-[180%] sm:w-[110%] dark:opacity-80"
style="background: radial-gradient(ellipse at 50% 80%,rgba(194,97,254,0.15),hsla(0,0%,100%,0));"
>}}
{{< hextra/feature-card
title="Markdown 写作"
subtitle="只需使用 Markdown 进行编辑。多样的 Shortcode 组件开箱即用。"
class="aspect-auto md:aspect-[1.1/1] max-lg:min-h-[340px]"
image="/images/hextra-markdown.webp"
imageClass="top-[40%] left-[36px] w-[180%] sm:w-[110%] dark:opacity-80"
style="background: radial-gradient(ellipse at 50% 80%,rgba(142,53,74,0.15),hsla(0,0%,100%,0));"
>}}
{{< hextra/feature-card
title="全文搜索"
subtitle="内置 FlexSearch 全文搜索,无需额外设置。"
class="aspect-auto md:aspect-[1.1/1] max-md:min-h-[340px]"
image="/images/hextra-search.webp"
imageClass="top-[40%] left-[36px] w-[110%] sm:w-[110%] dark:opacity-80"
style="background: radial-gradient(ellipse at 50% 80%,rgba(221,210,59,0.15),hsla(0,0%,100%,0));"
>}}
{{< hextra/feature-card
title="轻如羽毛"
subtitle="使用 Hextra 无需依赖 Node.js。由 Hugo 提供支持Hugo 是最快的静态网站生成器之一,只需一个二进制文件即可在数秒内创建网站。"
>}}
{{< hextra/feature-card
title="响应式布局,暗黑模式"
subtitle="适应不同的屏幕尺寸。内置暗黑模式支持,并根据用户的系统偏好自动切换。"
>}}
{{< hextra/feature-card
title="免费构建和托管"
subtitle="使用 GitHub Actions 进行构建,并在 GitHub Pages 上免费托管。也可以托管在任何静态托管服务上。"
>}}
{{< hextra/feature-card
title="多语言轻松实现"
subtitle="仅需通过在 Markdown 文件后添加语言代码即可创建多语言页面。向您的站点添加 i18n 支持直观易行。"
>}}
{{< hextra/feature-card
title="还有更多..."
icon="sparkles"
subtitle="代码高亮 / 目录 / SEO / RSS / LaTeX 公式 / Mermaid 图标 / 自定义 / 等等..."
>}}
{{< /hextra/feature-grid >}}

View File

@ -0,0 +1,20 @@
---
title: "このサイトについて"
toc: false
---
Hextraは、現代的な静的ウェブサイトを構築するためのシンプルで高速で柔軟なテーマとして設計されています。特にドキュメンテーションウェブサイトに適していますが、ブログ、ポートフォリオなどのさまざまなタイプのサイトにも使用できます。
Hugoは、Jekyllと同様に静的サイトジェネレーターです。Hugoの特徴は、単一のバイナリであることで、さまざまなプラットフォームで簡単にインストールして実行できることです。また、数千ページのサイトをミリ秒単位でレンダリングできるほど非常に高速で信頼性があります。
Hextraは、最小限のフットプリントに焦点を当てた考え方で構築されています。始めるためには、Node.jsのような追加の依存関係は必要ありません。必要なのは、単一のYAML設定ファイルと、Markdownのコンテンツだけです。そのため、ツールのセットアップではなく、質の高いコンテンツの作成に集中できます。
## クレジット
Hextraをビルドするには、次のツールとインスピレーションが必要です
- [Hugo](https://gohugo.io/)
- [Tailwind CSS](https://tailwindcss.com/)
- [Heroicons](https://heroicons.com/)
- [Nextra](https://nextra.vercel.app/)
- [Next.js](https://nextjs.org/)

View File

@ -1,10 +1,3 @@
---
title: "Blog"
---
<div style="text-align: center; margin-top: 1em;">
{{< hextra/hero-badge link="index.xml" >}}
<span>RSS Feed</span>
{{< icon name="rss" attributes="height=14" >}}
{{< /hextra/hero-badge >}}
</div>

View File

@ -2,16 +2,8 @@
title: Markdown Syntax Guide
date: 2020-01-01
authors:
- name: imfing
link: https://github.com/imfing
image: https://github.com/imfing.png
- name: Octocat
link: https://github.com/octocat
image: https://github.com/octocat.png
tags:
- Markdown
- Example
- Guide
- name: John Doe
link: https://example.com/johndoe
excludeSearch: true
---

View File

@ -0,0 +1,17 @@
---
linkTitle: "ドキュメンテーション"
title: Hextraへようこそ
---
👋 こんにちはHextraドキュメンテーションへようこそ
<!--more-->
## Hextraとは
Hextraは、[Hugo][hugo]テーマの一つで、[Tailwind CSS][tailwind-css]を使用して作られた、現代的で高速なバッテリー内蔵のテーマです。
ドキュメンテーション、ブログ、ウェブサイトの美しいウェブサイトを構築するために設計され、様々な要件に対応するための機能と柔軟性を提供します。
[hugo]: https://gohugo.io/
[flex-search]: https://github.com/nextapps-de/flexsearch
[tailwind-css]: https://tailwindcss.com/

View File

@ -10,15 +10,15 @@ title: Introduction
## What is Hextra?
Hextra is a modern, fast and batteries-included [Hugo][hugo] theme built with [Tailwind CSS][tailwind-css].
Designed for building beautiful websites for documentation, blogs, and websites, it provides out-of-the-box features and flexibility to meet various requirements.
Designed for building beautiful websites for documentation, blogs and websites, it provides out-of-the-box features and flexibility to meet various requirements.
## Features
- **Beautiful Design** - Inspired by Nextra, Hextra utilizes Tailwind CSS to offer a modern design that makes your site look outstanding.
- **Responsive Layout and Dark Mode** - It looks great on all devices, from mobile, tablet to desktop. Dark mode is also supported to accommodate various lighting conditions.
- **Fast and Lightweight** - Powered by Hugo, a lightning-fast static-site generator housed in a single binary file, Hextra keeps its footprint minimal. No JavaScript or Node.js are needed to use it.
- **Responsive Layout and Dark Mode** - It looks great on all devices, from mobile, tablet to desktop. Dark mode is also supported to accomodate various lighting conditions.
- **Fast and Lightweight** - Powered by Hugo, a lightning-fast static-site generator housed in a single binary file, Hextra keeps its footprint minimal. No Javascript or Node.js are needed to use it.
- **Full-text Search** - Built-in offline full-text search powered by FlexSearch, no additional configuration required.
- **Battery-included** - Markdown, syntax highlighting, LaTeX math formulae, diagrams and Shortcodes elements to enhance your content. Table of contents, breadcrumbs, pagination, sidebar navigation and more are all automatically generated.
- **Battery-included** - Markdown, syntax highlighting, LaTeX math formulae, diagrams and Shortcodes elements to enhance your content. Table of contents, breadcumbs, pagination, sidebar navigation and more are all automatically generated.
- **Multi-language and SEO Ready** - Multi-language sites made easy with Hugo's multilingual mode. Out-of-the-box support is included for SEO tags, Open Graph, and Twitter Cards.
## Questions or Feedback?

View File

@ -1,39 +0,0 @@
---
title: 评论系统
linkTitle: Comments
---
Hextra 支持在你的网站中添加评论系统。
目前已经支持 [giscus](https://giscus.app/).
<!--more-->
## giscus
[giscus](https://giscus.app/) 是由 [GitHub Discussions](https://docs.github.com/en/discussions)驱动的评论系统。Giscus 免费并且开源。
如需启用 Giscus, 你需要在配置文件中添加以下内容:
```yaml {filename="hugo.yaml"}
params:
comments:
enable: false
type: giscus
giscus:
repo: <repository>
repoId: <repository ID>
category: <category>
categoryId: <category ID>
```
Giscus 配置可以参考 [giscus.app](https://giscus.app/),还可以在那里找到更多详细信息。
可以在 front matter 中启用或禁用特定页面的评论:
```yaml {filename="content/docs/about.md"}
---
title: About
comments: true
---
```

View File

@ -47,8 +47,8 @@ The primary color of the theme can be customized by setting the `--primary-hue`
List of available syntax highlighting themes are available at [Chroma Styles Gallery](https://xyproto.github.io/splash/docs/all.html). The stylesheet can be generated using the command:
```shell
hugo gen chromastyles --style=github
```bash
$ hugo gen chromastyles --style=github
```
To override the default syntax highlighting theme, we can add the generated styles to the custom CSS file.
@ -70,4 +70,4 @@ For further information, refer to the [Hugo Templates](https://gohugo.io/templat
## Further Customization
Didn't find what you were looking for? Feel free to [open a discussion](https://github.com/imfing/hextra/discussions) or make a contribution to the theme!
Didn't find what you were looking for? Feel free to [open an issue](https://github.com/imfing/hextra/issues) or make a contribution to the theme!

View File

@ -30,10 +30,10 @@ Hextra 在 `hugo.yaml` 中提供了一些自定义选项来配置主题。
### 代码高亮
代码高亮风格的详细信息可在 [Chroma Styles Gallery](https://xyproto.github.io/splash/docs/all.html) 中找到。可以使用以下命令生成样式表:
代码高亮风格的详细信息可在 [Chroma Styles Gallery](https://xyproto.github.io/splash/docs/all.html) 中找到。 可以使用以下命令生成样式表:
```shell
hugo gen chromastyles --style=github
```bash
$ hugo gen chromastyles --style=github
```
可将生成的样式添加到自定义 CSS 文件中以覆盖默认代码高亮样式。
@ -55,4 +55,4 @@ layouts/partials/custom/head-end.html
## 进一步定制 Hextra
没有找到你想修改的内容?在 GitHub 上[创建 Discussion](https://github.com/imfing/hextra/discussions) 或为 Hextra 贡献你的智慧!
没有找到你想修改的东西?在 GitHub 上[创建 Issues](https://github.com/imfing/hextra/issues) 或为 Hextra 贡献你的智慧!

View File

@ -0,0 +1,6 @@
---
title: はじめに
weight: 1
---
プロジェクトの紹介。

View File

@ -9,28 +9,27 @@ prev: /docs
{{< icon "github" >}}&nbsp;[imfing/hextra-starter-template](https://github.com/imfing/hextra-starter-template)
You could quickly get started by using the above template repository.
You will be able to quickly get started by using the above template repository.
<img src="https://docs.github.com/assets/cb-77734/mw-1440/images/help/repository/use-this-template-button.webp" width="500">
We have provided a [GitHub Actions workflow](https://docs.github.com/en/pages/getting-started-with-github-pages/configuring-a-publishing-source-for-your-github-pages-site#publishing-with-a-custom-github-actions-workflow) which can help automatically build and deploy your site to GitHub Pages, and host it for free.
For more options, check out [Deploy Site](../guide/deploy-site).
[🌐 Demo ↗](https://imfing.github.io/hextra-starter-template/)
## Start as New Project
There are two main ways to add the Hextra theme to your Hugo project:
There are two main ways to add the Hextra theme to your Hugo project.
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.
2. **Git Submodule**: Alternatively, add Hextra as a [Git Submodule](https://git-scm.com/book/en/v2/Git-Tools-Submodules). The theme is downloaded by Git and stored in your project's `themes` folder.
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 software installed:
Before starting, you need to have the following softwares installed:
- [Hugo (extended version)](https://gohugo.io/installation/)
- [Git](https://git-scm.com/)
@ -43,18 +42,18 @@ Before starting, you need to have the following software installed:
### Initialize a new Hugo site
```shell
hugo new site my-site --format=yaml
$ hugo new site my-site --format=yaml
```
### Configure Hextra theme via module
```shell
# initialize hugo module
cd my-site
hugo mod init github.com/username/my-site
$ cd my-site
$ hugo mod init github.com/username/my-site
# add Hextra theme
hugo mod get github.com/imfing/hextra
$ hugo mod get github.com/imfing/hextra
```
Configure `hugo.yaml` to use Hextra theme by adding the following:
@ -67,20 +66,20 @@ module:
### Create your first content pages
Create 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
hugo new content/_index.md
hugo new content/docs/_index.md
$ hugo new content/_index.md
$ hugo new content/docs/_index.md
```
### Preview the site locally
```shell
hugo server --buildDrafts --disableFastRender
$ hugo server --buildDrafts --disableFastRender
```
Voila, your new site preview is available at `http://localhost:1313/`.
Voila! You can see your new site at `http://localhost:1313/`.
{{% /steps %}}
@ -90,10 +89,10 @@ Voila, your new site preview is available at `http://localhost:1313/`.
To update all Hugo modules in your project to their latest versions, run the following command:
```shell
hugo mod get -u
$ hugo mod get -u
```
To update Hextra to the [latest released version](https://github.com/imfing/hextra/releases), run the following command:
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
@ -107,7 +106,7 @@ See [Hugo Modules](https://gohugo.io/hugo-modules/use-modules/#update-all-module
#### Prerequisites
Before starting, you need to have the following software installed:
Before starting, you need to have the following softwares installed:
- [Hugo (extended version)](https://gohugo.io/installation/)
- [Git](https://git-scm.com/)
@ -119,7 +118,7 @@ Before starting, you need to have the following software installed:
### Initialize a new Hugo site
```shell
hugo new site my-site --format=yaml
$ hugo new site my-site --format=yaml
```
### Add Hextra theme as a Git submodule
@ -136,20 +135,20 @@ theme: hextra
### Create your first content pages
Create 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
hugo new content/_index.md
hugo new content/docs/_index.md
$ hugo new content/_index.md
$ hugo new content/docs/_index.md
```
### Preview the site locally
```shell
hugo server --buildDrafts --disableFastRender
$ hugo server --buildDrafts --disableFastRender
```
Your new site preview is available at `http://localhost:1313/`.
Voila! You can see your new site at `http://localhost:1313/`.
{{% /steps %}}
@ -160,7 +159,7 @@ When using [CI/CD](https://en.wikipedia.org/wiki/CI/CD) for Hugo website deploym
git submodule update --init
```
Failure to run this command results in the theme folder not being populated with Hextra theme files, leading to a build failure.
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?" %}}
@ -168,10 +167,10 @@ Failure to run this command results in the theme folder not being populated with
To update all submodules in your repository to their latest commits, run the following command:
```shell
git submodule update --remote
$ git submodule update --remote
```
To update Hextra to the latest commit, run the following command:
To update only Hextra to the latest commit, run the following command:
```shell
git submodule update --remote themes/hextra

View File

@ -26,21 +26,23 @@ prev: /docs
[Hugo 模块](https://gohugo.io/hugo-modules/)是管理 Hugo 主题的推荐方式。要使用 Hugo 模块,我们需要安装 [Git](https://git-scm.com/) 和 [Go](https://go.dev/)。
{{% steps %}}
### 初始化 Hugo 站点
```shell
hugo new site my-site --format=yaml
```bash
$ hugo new site my-site --format=yaml
```
### 通过 Hugo Module 安装
### 通过模块配置 Hextra 主题
```shell
# 初始化 Hugo 模块
cd my-site
hugo mod init github.com/username/my-site
$ cd my-site
$ hugo mod init github.com/username/my-site
# 添加 Hextra
hugo mod get github.com/imfing/hextra
$ hugo mod get github.com/imfing/hextra
```
编辑 `hugo.yaml` 以启用 Hextra
@ -51,92 +53,31 @@ module:
- path: github.com/imfing/hextra
```
### 通过 Git Submodule 安装
#### 先决条件
在我们开始之前,你必须先确保以下软件已经安装:
- [Hugo (extended version)](https://gohugo.io/installation/)
- [Git](https://git-scm.com/)
#### 步骤
{{% steps %}}
### 初始化 Hugo 站点
```shell
hugo new site my-site --format=yaml
```
### 将 Hextra 添加为 Git Submodule
```shell
git submodule add https://github.com/imfing/hextra.git themes/hextra
```
添加以下内容来配置 `hugo.yaml` 以使用 Hextra
```yaml
theme: hextra
```
### 创建你的第一个内容页
让我们为主页和文档页面创建一个新的内容页面:
```shell
hugo new content/_index.md
hugo new content/docs/_index.md
$ hugo new content/_index.md
$ hugo new content/docs/_index.md
```
### 在本地预览站点
```shell
hugo server --buildDrafts --disableFastRender
$ hugo server --buildDrafts --disableFastRender
```
瞧!你现在可以在 `http://localhost:1313/` 看到你的新站点。
{{% /steps %}}
使用 [CI/CD](https://en.wikipedia.org/wiki/CI/CD) 进行部署时,必须确保在运行 `hugo` 命令之前执行以下命令。
```shell
git submodule update --init
```
如果不运行此命令theme 中将不会存在 Hextra 文件,进而导致构建失败。
{{% details title="如何更新主题?" %}}
如需把项目中所有的 Hugo Modules 都升级到最新,在终端中运行此命令:
```shell
hugo mod get -u
```
如需把 Hextra 升级到[最新的发行版本](https://github.com/imfing/hextra/releases), 在终端中运行此命令:
```shell
hugo mod get -u github.com/imfing/hextra
```
如果你需要获得更多信息,参见 [Hugo Modules](https://gohugo.io/hugo-modules/use-modules/#update-all-modules).
{{% /details %}}
## 接下来
探索这些文档以便添加更多内容:
你可以探索以下部分来添加更多内容:
{{< cards >}}
{{< card link="../guide/organize-files" title="Organize Files" icon="document-duplicate" >}}
{{< card link="../guide/configuration" title="Configuration" icon="adjustments" >}}
{{< card link="../guide/organize-files" title="目录结构" icon="document-duplicate" >}}
{{< card link="../guide/configuration" title="配置文件指南" icon="adjustments" >}}
{{< card link="../guide/markdown" title="Markdown" icon="markdown" >}}
{{< /cards >}}

View File

@ -7,7 +7,7 @@ sidebar:
open: true
---
Explore the following sections to learn how to use Hextra:
Explore the following sections to learn to compose content using Hextra:
<!--more-->
@ -19,5 +19,4 @@ Explore the following sections to learn how to use Hextra:
{{< card link="latex" title="LaTeX" icon="variable" >}}
{{< card link="diagrams" title="Diagrams" icon="chart-square-bar" >}}
{{< card link="shortcodes" title="Shortcodes" icon="template" >}}
{{< card link="deploy-site" title="Deploy Site" icon="server" >}}
{{< /cards >}}

View File

@ -90,16 +90,6 @@ params:
For the main sidebar, it is automatically generated from the structure of the content directory.
See the [Organize Files](/docs/guide/organize-files) page for more details.
To exclude a single page from the left sidebar, set the `sidebar.exclude` parameter in the front matter of the page:
```yaml {filename="content/docs/guide/configuration.md"}
---
title: Configuration
sidebar:
exclude: true
---
```
### Extra Links
Sidebar extra links are defined under the `menu.sidebar` section in the config file:
@ -139,17 +129,17 @@ To configure the page edit link, we can set the `params.editURL.base` parameter
```yaml {filename="hugo.yaml"}
params:
editURL:
enable: true
base: "https://github.com/your-username/your-repo/edit/main"
```
The edit links will be automatically generated for each page based on the provided url as root directory.
If you want to set edit link for a specific page, you can set the `editURL` parameter in the front matter of the page:
The edit links will be automatically generated for each page.
If you want to set edit link for a specific page, you can set the `params.editURL` parameter in the front matter of the page:
```yaml {filename="content/docs/guide/configuration.md"}
---
title: Configuration
editURL: "https://example.com/edit/this/page"
params:
editURL: "https://example.com/edit/this/page"
---
```
@ -262,10 +252,8 @@ excludeSearch: true
### Google Analytics
To enable [Google Analytics](https://marketingplatform.google.com/about/analytics/), set `services.googleAnalytics.ID` flag in `hugo.yaml`:
To enable Google Analytics, set the `googleAnalytics` parameter in the config file:
```yaml {filename="hugo.yaml"}
services:
googleAnalytics:
ID: G-MEASUREMENT_ID
googleAnalytics: G-XXXXXXXXXX
```

View File

@ -38,7 +38,7 @@ menu:
icon: github
```
有几种不同类型的菜单项
有几种不同类型的菜单项:
1. Link to a page in the site with `pageRef`
```yaml
@ -114,126 +114,12 @@ params:
```
将为每个页面自动生成编辑链接。
如需为特定页面设置编辑链接,可以在页面的 `front matter` 中设置 `editURL`
如需为特定页面设置编辑链接,可以在页面的 `front matter` 中设置 `params.editURL`
```yaml {filename="content/docs/guide/configuration.md"}
---
title: Configuration
editURL: "https://example.com/edit/this/page"
params:
editURL: "https://example.com/edit/this/page"
---
```
## Footer
### 版权声明
如需修改网站页脚中显示的版权文本您需要创建一个名为“i18n/en.yaml”的文件。
在此文件中,填写新的版权文本,像这样:
```yaml {filename="i18n/en.yaml"}
copyright: "© 2023 YOUR TEXT HERE"
```
你可以在 GitHub 存储库中找到示例 [`i18n/en.yaml`](https://github.com/imfing/hextra/blob/main/i18n/en.yaml) 文件。另外,你可以在版权文本中使用 Markdown 格式。
## 其他
### Favicon
如需自定义 [favicon](https://en.wikipedia.org/wiki/Favicon),请将图标文件放在 `static` 文件夹下以覆盖 [主题中的默认 favicon](https://github.com/imfing/hextra/tree/main/static)
{{< filetree/container >}}
{{< filetree/folder name="static" >}}
{{< filetree/file name="android-chrome-192x192.png" >}}
{{< filetree/file name="android-chrome-512x512.png" >}}
{{< filetree/file name="apple-touch-icon.png" >}}
{{< filetree/file name="favicon-16x16.png" >}}
{{< filetree/file name="favicon-32x32.png" >}}
{{< filetree/file name="favicon-dark.svg" >}}
{{< filetree/file name="favicon.ico" >}}
{{< filetree/file name="favicon.svg" >}}
{{< filetree/file name="site.webmanifest" >}}
{{< /filetree/folder >}}
{{< /filetree/container >}}
在您的项目中包含 `favicon.ico` 和 `favicon.svg` 文件,以确保网站的网站图标正确显示。
虽然 `favicon.ico` 通常适用于较旧的浏览器,但 `favicon.svg` 受到现代浏览器的支持,所以更现代的做法是添加 `favicon-dark.svg` 以便在黑暗模式下提供较好的体验体验。
请随意使用 [favicon.io](https://favicon.io/) 或 [favycon](https://github.com/ruisaraiva19/favycon) 等工具来生成这些图标。
### 颜色主题配置
使用`theme`设置来配置默认主题模式和切换按钮,允许访问者在浅色或深色模式之间切换。
```yaml {filename="hugo.yaml"}
params:
theme:
# light | dark | system
default: system
displayToggle: true
```
`theme.default` 的可选项:
- `light` - 仅使用浅色模式
- `dark` - 仅使用神色模式
- `system` - 跟随系统
`theme.displayToggle` 控制显示用于更改主题的切换按钮。
当设置为“true”时访问者可以在浅色或深色模式之间切换覆盖默认设置。
### 页宽
页面的宽度可以通过配置文件中的`params.page.width`参数来调整:
```yaml {filename="hugo.yaml"}
params:
page:
# full (100%), wide (90rem), normal (1280px)
width: wide
```
有三个可选项:`full`, `wide`, and `normal`. 默认的页宽模式是 `normal`.
同样的,导航栏和 `footer` 的宽度也可通过 `params.navbar.width` 和 `params.footer.width` 调整。
### 搜索
默认情况下启用由 [FlexSearch](https://github.com/nextapps-de/flexsearch) 提供全文搜索。
要自定义搜索索引,请在配置文件中设置 `params.search.flexsearch.index`
```yaml {filename="hugo.yaml"}
params:
# Search
search:
enable: true
type: flexsearch
flexsearch:
# index page by: content | summary | heading | title
index: content
```
`flexsearch.index` 的可选项:
- `content` - 全内容搜索
- `summary` - 概述 [Hugo Content Summaries](https://gohugo.io/content-management/summaries/)
- `heading` - 一级和二级标题
- `title` - 仅搜索标题
要从搜索索引中排除页面,更改 front matter 中的 `excludeSearch: true`:
```yaml {filename="content/docs/guide/configuration.md"}
---
title: Configuration
excludeSearch: true
---
```
### Google Analytics
要启用 [Google Analytics](https://marketingplatform.google.com/about/analytics/),设置 `services.googleAnalytics.ID`:
```yaml {filename="hugo.yaml"}
services:
googleAnalytics:
ID: G-MEASUREMENT_ID
```

View File

@ -1,161 +0,0 @@
---
title: Deploy Site
prev: /docs/guide/shortcodes
next: /docs/advanced
---
Hugo generates static websites, allowing for flexible hosting options.
This page provides guides for deploying your Hextra site on various platforms.
<!--more-->
## GitHub Pages
[GitHub Pages](https://docs.github.com/pages) is the recommended way to deploy and host your website for free.
If you bootstrap the site using [hextra-starter-template](https://github.com/imfing/hextra-starter-template), it has provided GitHub Actions workflow out-of-the-box that helps automatically deploy to GitHub Pages.
{{% details title="GitHub Actions Configuration" closed="true" %}}
Below is an example configuration from [hextra-starter-template](https://github.com/imfing/hextra-starter-template):
```yaml {filename=".github/workflows/pages.yaml"}
# Sample workflow for building and deploying a Hugo site to GitHub Pages
name: Deploy Hugo site to Pages
on:
# Runs on pushes targeting the default branch
push:
branches: ["main"]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
permissions:
contents: read
pages: write
id-token: write
# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
concurrency:
group: "pages"
cancel-in-progress: false
# Default to bash
defaults:
run:
shell: bash
jobs:
# Build job
build:
runs-on: ubuntu-latest
env:
HUGO_VERSION: 0.117.0
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0 # Fetch all history for .GitInfo and .Lastmod
- name: Setup Go
uses: actions/setup-go@v4
with:
go-version: '1.21'
- name: Setup Hugo
uses: peaceiris/actions-hugo@v2
with:
hugo-version: '0.117.0'
extended: true
- name: Build with Hugo
env:
# For maximum backward compatibility with Hugo modules
HUGO_ENVIRONMENT: production
HUGO_ENV: production
run: |
hugo \
--gc --minify \
--baseURL "https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/"
- name: Upload artifact
uses: actions/upload-pages-artifact@v2
with:
path: ./public
# Deployment job
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
needs: build
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v2
```
{{% /details %}}
{{< callout >}}
In your repository settings, set the **Pages** > **Build and deployment** > **Source** to **GitHub Actions**:
![](https://user-images.githubusercontent.com/5097752/266784808-99676430-884e-42ab-b901-f6534a0d6eee.png)
{{< /callout >}}
By default, the above GitHub Actions workflow `.github/workflows/pages.yaml` assumes that the site is deploying to `https://<USERNAME>.github.io/<REPO>/`.
If you are deploying to `https://<USERNAME>.github.io/` then modify the `--baseURL`:
```yaml {filename=".github/workflows/pages.yaml",linenos=table,linenostart=54,hl_lines=[4]}
run: |
hugo \
--gc --minify \
--baseURL "https://${{ github.repository_owner }}.github.io/"
```
If you are deploying to your own domain, please change the `--baseURL` value accordingly.
## Cloudflare Pages
1. Put your site source code in a Git repository (e.g. GitHub)
2. Log in to the [Cloudflare dashboard](https://dash.cloudflare.com/) and select your account
3. In Account Home, select **Workers & Pages** > **Create application** > **Pages** > **Connect to Git**
4. Select the repository, and in the **Set up builds and deployments** section, provide the following information:
| Configuration | Value |
| ----------------- | -------------------- |
| Production branch | `main` |
| Build command | `hugo --gc --minify` |
| Build directory | `public` |
For more details, check out:
- [Deploy a Hugo site](https://developers.cloudflare.com/pages/framework-guides/deploy-a-hugo-site/#deploy-with-cloudflare-pages).
- [Language support and tools](https://developers.cloudflare.com/pages/platform/language-support-and-tools/).
## Netlify
1. Push your code to your Git repository (GitHub, GitLab, etc.)
2. [Import the project](https://app.netlify.com/start) to Netlify
3. If you are not using [hextra-starter-template][hextra-starter-template], configure the following manually:
- Configure the Build command to `hugo --gc --minify`
- Specify the Publish directory to `public`
- Add Environment variable `HUGO_VERSION` and set to `0.119.0`
4. Deploy!
Check [Hugo on Netlify](https://docs.netlify.com/integrations/frameworks/hugo/) for more details.
## Vercel
1. Push your code to your Git repository (GitHub, GitLab, etc.)
2. Go to [Vercel Dashboard](https://vercel.com/dashboard) and import your Hugo project
3. Configure the project, select Hugo as Framework Preset
4. Override the Build Command and Install command:
1. Set Build Command to `hugo --gc --minify`
2. Set Install Command to `yum install golang`
![Vercel Deployment Configuration](https://github.com/imfing/hextra/assets/5097752/887d949b-8d05-413f-a2b4-7ab92192d0b3)

View File

@ -4,7 +4,7 @@ weight: 6
next: /docs/guide/shortcodes
---
目前Hextra 支持 [Mermaid](#mermaid) 的图表。
目前Hextra 支持 [Mermain](#mermaid) 的图表。
<!--more-->
@ -12,7 +12,7 @@ next: /docs/guide/shortcodes
[Mermaid](https://github.com/mermaid-js/mermaid#readme) 是一个基于 JavaScript 的图表绘制工具,它的文本定义和 Markdown 类似,可在浏览器中动态创建图表。例如:流程图、序列图、饼图等。
在 Hextra 中使用 Mermaid 就像使用代码块一样简单:
在 Hextra 中使用 Mermain 就像使用代码块一样简单:
````markdown
```mermaid

View File

@ -7,7 +7,7 @@ prev: /docs/guide
## Directory Structure
By default, Hugo searches for Markdown files in the `content` directory, and the structure of the directory determines the final output structure of your website.
Take this site as an example:
Take the example site as an example:
<!--more-->
@ -45,28 +45,6 @@ content
└── post-1.md // <- /blog/post-1/
```
## Layouts
Hextra offers three layouts for different content types:
| Layout | Directory | Features |
| :-------- | :-------------------- | :--------------------------------------------------------------- |
| `docs` | `content/docs/` | Ideal for structured documentation, same as this section. |
| `blog` | `content/blog/` | For blog postings, with both listing and detailed article views. |
| `default` | All other directories | Single-page article view without sidebar. |
To customize a section to mirror the behavior of a built-in layout, specify the desired type in the front matter of the section's `_index.md`.
```yaml {filename="content/my-docs/_index.md"}
---
title: My Docs
cascade:
type: docs
---
```
The above example configuration ensures that the content files inside `content/my-docs/` will be treated as documentation (`docs` type) by default.
## Sidebar Navigation
The sidebar navigation is generated automatically based on the content organization alphabetically. To manually configure the sidebar order, we can use the `weight` parameter in the front matter of the Markdown files.
@ -84,8 +62,7 @@ weight: 2
## Configure Content Directory
By default, the root `content/` directory is used by Hugo to build the site.
If you need to use a different directory for content, for example `docs/`, this can be done by setting the [`contentDir`](https://gohugo.io/getting-started/configuration/#contentdir) parameter in the site configuration `hugo.yaml`.
If we need to use a different directory for our content, we can do so by setting the [`contentDir`](https://gohugo.io/getting-started/configuration/#contentdir) parameter in our site configuration file.
## Add Images

View File

@ -0,0 +1,6 @@
---
title: コンポーネント
weight: 2
---
Hextraは、[Hugo Shortcodes](https://gohugo.io/content-management/shortcodes/)に基づいたさまざまな組み込みコンポーネントを提供しています。

View File

@ -24,7 +24,7 @@ This will be hidden by default.
## Usage
````markdown
````
{{%/* details title="Details" */%}}
This is the content of the details.
@ -34,7 +34,7 @@ Markdown is **supported**.
{{%/* /details */%}}
````
````markdown
````
{{%/* details title="Click me to reveal" closed="true" */%}}
This will be hidden by default.

View File

@ -8,9 +8,7 @@ To use this shortcode inline, inline shortcode needs to be enabled in the config
enableInlineShortcodes: true
```
List of available icons can be found in [`data/icons.yaml`](https://github.com/imfing/hextra/blob/main/data/icons.yaml).
<!--more-->
The list of available icons can be found in `data/icons.yaml`.
## Example
@ -27,20 +25,14 @@ List of available icons can be found in [`data/icons.yaml`](https://github.com/i
[Heroicons](https://v1.heroicons.com/) v1 outline icons are available out of the box.
### How to add your own icons
You can also add your own icons by adding them to `data/icon.yaml`:
Create `data/icons.yaml` file, then add your own SVG icons in the following format:
```yaml {filename="data/icons.yaml"}
```yaml {filename="data/icon.yaml"}
your-icon: <svg>your icon svg content</svg>
```
It then can be used in the shortcode like this:
which can then be used like this:
```
{{</* icon "your-icon" */>}}
{{</* card icon="your-icon" */>}}
```
Tip: [Iconify Design](https://iconify.design/) is a great place to find SVG icons for your site.

View File

@ -1,6 +1,6 @@
---
title: Tabs
next: /docs/guide/deploy-site
next: /docs/advanced/
---
## Example

View File

@ -86,4 +86,4 @@ By default, copy button is enabled for code blocks.
## Supported Languages
For a list of supported languages, please see the [Chroma documentation](https://github.com/alecthomas/chroma#supported-languages).
For a list of supported languages, please see [Chroma's documentation](https://github.com/alecthomas/chroma#supported-languages).

View File

@ -12,8 +12,7 @@ Open source projects powered by Hextra.
</p>
{{< cards >}}
{{< card link="https://developers.osuny.org" title="Osuny" image="https://raw.githubusercontent.com/noesya/osuny-developers/main/static/images/showcase-hextra/screenshot.png" imageStyle="object-fit:cover; aspect-ratio:16/9;" >}}
{{< card link="https://getporter.org/" title="Porter" image="https://repository-images.githubusercontent.com/155893691/aa249c80-fcf3-11ea-93b0-30079e8d7de4" imageStyle="object-fit:cover; aspect-ratio:16/9;" >}}
{{< card link="https://lutheranconfessions.org/" title="LutheranConfessions" image="https://github.com/imfing/hextra/assets/5097752/ad6625e4-88cd-4cad-b102-5399997d0359" imageStyle="object-fit:cover; aspect-ratio:16/9;" >}}
{{< card link="https://github.com/imfing/hextra-starter-template/" title="Hextra Starter Template" image="https://user-images.githubusercontent.com/5097752/263551418-c403b9a9-a76c-47a6-8466-513d772ef0b7.jpg" imageStyle="object-fit:cover; aspect-ratio:16/9;" >}}
{{< card link="/" title="Hextra Starter Template" image="https://user-images.githubusercontent.com/5097752/263551418-c403b9a9-a76c-47a6-8466-513d772ef0b7.jpg" imageStyle="object-fit:cover; aspect-ratio:16/9;" >}}
{{< /cards >}}

View File

@ -1,19 +0,0 @@
---
title: 项目展示
description: "由 Hextra 驱动的开源网站和项目。"
toc: false
layout: wide
---
<div class="mt-4"></div>
<p class="mb-12 text-center text-lg text-gray-500 dark:text-gray-400">
由 Hextra 驱动的开源网站和项目。
</p>
{{< cards >}}
{{< card link="https://developers.osuny.org" title="Osuny" image="https://raw.githubusercontent.com/noesya/osuny-developers/main/static/images/showcase-hextra/screenshot.png" imageStyle="object-fit:cover; aspect-ratio:16/9;" >}}
{{< card link="https://getporter.org/" title="Porter" image="https://repository-images.githubusercontent.com/155893691/aa249c80-fcf3-11ea-93b0-30079e8d7de4" imageStyle="object-fit:cover; aspect-ratio:16/9;" >}}
{{< card link="https://lutheranconfessions.org/" title="LutheranConfessions" image="https://github.com/imfing/hextra/assets/5097752/ad6625e4-88cd-4cad-b102-5399997d0359" imageStyle="object-fit:cover; aspect-ratio:16/9;" >}}
{{< card link="https://github.com/imfing/hextra-starter-template" title="Hextra Starter Template" image="https://user-images.githubusercontent.com/5097752/263551418-c403b9a9-a76c-47a6-8466-513d772ef0b7.jpg" imageStyle="object-fit:cover; aspect-ratio:16/9;" >}}
{{< /cards >}}

View File

@ -7,9 +7,7 @@ enableGitInfo: true
# enableEmoji: false
hasCJKLanguage: true
# services:
# googleAnalytics:
# ID: G-MEASUREMENT_ID
# googleAnalytics: G-XXXXXXXXXX
outputs:
home: [HTML]
@ -22,10 +20,14 @@ languages:
languageName: English
weight: 1
title: Hextra
ja:
languageName: 日本語
weight: 2
title: "Hextra テーマ"
zh-cn:
languageName: 简体中文
languageCode: zh-CN
weight: 2
weight: 3
title: Hextra
module:
@ -113,7 +115,6 @@ params:
displayToggle: true
footer:
enable: true
displayCopyright: true
displayPoweredBy: true
width: normal
@ -135,10 +136,6 @@ params:
enable: true
base: "https://github.com/imfing/hextra/edit/main/exampleSite/content"
blog:
list:
displayTags: true
comments:
enable: false
type: giscus

View File

@ -66,14 +66,13 @@
"[-webkit-touch-callout:none]",
"[counter-reset:step]",
"[hyphens:auto]",
"[transition:background-color_1.5s_ease]",
"[text-underline-position:from-font]",
"[word-break:break-word]",
"absolute",
"active:bg-gray-400/20",
"active:opacity-50",
"active:shadow-gray-200",
"active:shadow-sm",
"align-[-2.5px]",
"align-text-bottom",
"appearance-none",
"aspect-auto",
@ -91,7 +90,6 @@
"before:pointer-events-none",
"before:transition-transform",
"before:w-px",
"bg-black/80",
"bg-black/[.05]",
"bg-blue-100",
"bg-clip-text",
@ -161,7 +159,6 @@
"cursor-pointer",
"dark:before:bg-neutral-800",
"dark:before:invert",
"dark:bg-black/60",
"dark:bg-blue-900/30",
"dark:bg-dark",
"dark:bg-dark/50",
@ -236,12 +233,11 @@
"duration-200",
"duration-75",
"ease-in",
"ease-in-out",
"filename",
"first:mt-0",
"fixed",
"flex",
"flex-col",
"flex-wrap",
"focus:bg-white",
"focus:outline-none",
"focus:ring-4",
@ -259,8 +255,6 @@
"gap-1",
"gap-2",
"gap-4",
"gap-x-1.5",
"gap-y-2",
"grid",
"grid-cols-1",
"group",
@ -269,7 +263,6 @@
"group-data-[theme=dark]:hidden",
"group-data-[theme=light]:hidden",
"group-hover/code:opacity-100",
"group-hover:underline",
"group-open:before:rotate-90",
"group/code",
"group/copybtn",
@ -319,7 +312,6 @@
"inline",
"inline-block",
"inline-flex",
"inset-0",
"inset-x-0",
"inset-y-0",
"items-center",
@ -410,10 +402,7 @@
"min-w-full",
"ml-1",
"ml-4",
"mobile-menu-overlay",
"mr-1",
"mr-2",
"mt-1",
"mt-1.5",
"mt-12",
"mt-16",
@ -466,6 +455,7 @@
"pr-[max(env(safe-area-inset-right),1.5rem)]",
"print:bg-transparent",
"print:hidden",
"pt-1",
"pt-4",
"pt-6",
"pt-8",
@ -596,7 +586,6 @@
"w-screen",
"whitespace-nowrap",
"xl:block",
"z-10",
"z-20",
"z-[-1]"
],

View File

@ -1,6 +0,0 @@
documentation: "文档"
showcase: "项目展示"
blog: "博客"
about: "关于"
more: "更多"
hugoDocs: "Hugo 文档 ↗"

View File

@ -1,14 +1,9 @@
backToTop: "Scroll to top"
changeLanguage: "Change language"
changeTheme: "Change theme"
copyCode: "Copy code"
copyright: "© 2023 Hextra Project."
dark: "Dark"
editThisPage: "Edit this page on GitHub →"
lastUpdated: "Last updated on"
light: "Light"
noResultsFound: "No results found."
onThisPage: "On this page"
poweredBy: "Powered by Hextra"
readMore: "Read more →"
searchPlaceholder: "Search..."

View File

@ -1,13 +1,7 @@
backToTop: "Subir al inicio"
changeLanguage: "Cambiar idioma"
changeTheme: "Cambiar tema"
copyright: "© 2023 Proyecto Hextra."
dark: "Oscuro"
onThisPage: "En esta página"
editThisPage: "Edita esta página en GitHub →"
lastUpdated: "Última actualización"
light: "Claro"
noResultsFound: "No hubo resultados."
onThisPage: "En esta página"
poweredBy: "Con tecnología de Hextra"
readMore: "Leer más →"
searchPlaceholder: "Buscar..."
backToTop: "Subir al inicio"
copyright: "© 2023 Hextra Project."

View File

@ -1,13 +0,0 @@
backToTop: "Revenir en haut"
changeLanguage: "Changer la langue"
changeTheme: "Thème d'affichage"
copyright: "© 2023 Hextra Project."
dark: "Sombre"
editThisPage: "Modifier cette page sur GitHub →"
lastUpdated: "Dernière modification"
light: "Clair"
noResultsFound: "Pas de résultats trouvés"
onThisPage: "Sur cette page"
poweredBy: "Propulsé par Hextra"
readMore: "Lire plus →"
searchPlaceholder: "Rechercher..."

View File

@ -1,13 +1,16 @@
backToTop: "トップにスクロール"
changeLanguage: "言語を変更"
changeTheme: "テーマを変更"
copyright: "© 2023 Hextra プロジェクト。"
dark: "ダーク"
editThisPage: "このページをGitHubで編集 →"
# Navbar
documentation: "ドキュメンテーション"
blog: "ブログ"
about: "このサイトについて"
more: "もっと"
hugoDocs: "Hugoドキュメント ↗"
searchPlaceholder: "検索ドキュメント..."
noResultsFound: "検索結果が見つかりませんでした"
onThisPage: "このページでは"
editThisPage: "このページをGitHubで編集する →"
lastUpdated: "最終更新日"
light: "ライト"
noResultsFound: "結果が見つかりませんでした。"
onThisPage: "このページの内容"
poweredBy: "提供元 Hextra"
readMore: "もっと読む →"
searchPlaceholder: "検索..."
copyright: "© 2023 Hextra Project."

View File

@ -2,12 +2,8 @@ backToTop: "맨위로 스크롤"
changeLanguage: "언어변경"
changeTheme: "테마변경"
copyright: "© 2023 Hextra Project."
dark: "어두운 테마"
editThisPage: "Github에서 편집하기 →"
lastUpdated: "마지막 수정일자"
light: "밝은 테마"
noResultsFound: "결과 없음"
onThisPage: "페이지 목차"
poweredBy: "제공 Hextra"
readMore: "더보기 →"
searchPlaceholder: "검색..."

View File

@ -1,13 +0,0 @@
backToTop: "Gå til toppen"
changeLanguage: "Endre språk"
changeTheme: "Endre tema"
copyright: "© 2023 Hextra-prosjektet."
dark: "Mørk"
editThisPage: "Rediger denne siden på GitHub →"
lastUpdated: "Sist oppdatert"
light: "Lys"
noResultsFound: "Fant ingen treff."
onThisPage: "På denne siden"
poweredBy: "Powered by Hextra"
readMore: "Les mer →"
searchPlaceholder: "Søk..."

View File

@ -1,13 +0,0 @@
backToTop: "Gå til toppen"
changeLanguage: "Endre språk"
changeTheme: "Endre tema"
copyright: "© 2023 Hextra-prosjektet."
dark: "Mørk"
editThisPage: "Rediger denne sida på GitHub →"
lastUpdated: "Sist oppdatert"
light: "Ljos"
noResultsFound: "Fann ingen treff."
onThisPage: "På denne sida"
poweredBy: "Powered by Hextra"
readMore: "Les meir →"
searchPlaceholder: "Søk..."

View File

@ -1,13 +1,7 @@
backToTop: "Voltar ao topo"
changeLanguage: "Mudar a língua"
changeTheme: "Mudar tema"
copyright: "© 2023 Projecto Hextra."
dark: "Escuro"
editThisPage: "Edita esta página no GitHub →"
lastUpdated: "Última modificação"
light: "Claro"
noResultsFound: "Nenhum resultado encontrado"
onThisPage: "Nesta página"
poweredBy: "Com a tecnologia de Hextra"
readMore: "Ler mais →"
searchPlaceholder: "Procurar..."
editThisPage: "Edita esta página no GitHub →"
lastUpdated: "Última actualização"
backToTop: "Voltar ao topo"
copyright: "© 2023 Projecto Hextra."

View File

@ -1,13 +1,5 @@
backToTop: "Tembeza hadi juu"
changeLanguage: "Badilisha lugha"
changeTheme: "Badilisha mandhari"
copyright: "© 2023 Hextra Project."
dark: "Meusi"
onThisPage: "Kwenye ukurasa huu"
editThisPage: "Hariri ukurasa huu kwenye GitHub →"
lastUpdated: "Ilisasishwa mwisho"
light: "Nuru"
noResultsFound: "Hakuna matokeo yalipopatikana."
onThisPage: "Kwenye ukurasa huu"
poweredBy: "Inaendeshwa na Hextra"
readMore: "Soma zaidi →"
searchPlaceholder: "Tafuta..."
backToTop: "Tembeza hadi juu"
copyright: "© 2023 Hextra Project."

View File

@ -1,13 +1,7 @@
backToTop: "Lướt lên đầu trang"
changeLanguage: "Đổi ngôn ngữ"
changeTheme: "Đổi chủ đề"
copyright: "© 2023 Hextra Project."
dark: "Tối"
onThisPage: "Ở trang này"
editThisPage: "Sửa trang này trên GitHub →"
lastUpdated: "Lần cuối cập nhật lúc"
light: "Sáng"
noResultsFound: "Không tìm thấy kết quả."
onThisPage: "Ở trang này"
poweredBy: "Chạy bởi Hextra"
readMore: "Đọc thêm →"
searchPlaceholder: "Tìm kiếm..."
backToTop: "Lướt lên đầu trang"
copyright: "© 2023 Hextra Project."

View File

@ -1,13 +1,17 @@
backToTop: "返回顶部"
changeLanguage: "切换语言"
changeTheme: "切换主题"
copyright: "© 2023 Hextra Project."
dark: "深色"
documentation: "文档"
blog: "博客"
about: "关于"
more: "更多"
hugoDocs: "Hugo 文档 ↗"
searchPlaceholder: "搜索文档..."
noResultsFound: "无结果"
onThisPage: "此页上"
editThisPage: "在 GitHub 上编辑此页 →"
lastUpdated: "最后更新于"
light: "浅色"
noResultsFound: "无结果"
onThisPage: "此页上"
poweredBy: " Hextra 驱动"
readMore: "更多 →"
searchPlaceholder: "搜索文档..."
backToTop: "返回顶部"
copyright: "© 2023 Hextra Project."

View File

@ -1,13 +1,15 @@
backToTop: "返回頂部"
changeLanguage: "切換語言"
changeTheme: "切換主題"
copyright: "© 2023 Hextra Project."
dark: "深色"
documentation: "文檔"
blog: "博客"
about: "關於"
more: "更多"
hugoDocs: "Hugo 文檔 ↗"
searchPlaceholder: "搜索文檔..."
noResultsFound: "無結果"
onThisPage: "此頁上"
editThisPage: "在 GitHub 上編輯此頁 →"
lastUpdated: "最後更新於"
light: "淺色"
noResultsFound: "無結果"
onThisPage: "此頁上"
poweredBy: "由 Hextra 驅動"
readMore: "更多 →"
searchPlaceholder: "搜尋文檔..."
copyright: "© 2023 Hextra Project."

View File

@ -1,7 +1,6 @@
{{- $class := .Attributes.class | default "" -}}
{{- $filename := .Attributes.filename | default "" -}}
{{- $lang := .Attributes.lang | default .Type -}}
{{- $copyCode := (T "copyCode") | default "Copy code" -}}
<div class="code-block relative mt-6 first:mt-0 group/code">
@ -9,14 +8,17 @@
<div class="filename">{{ $filename }}</div>
{{- end -}}
{{- if transform.CanHighlight $lang -}}
<div>{{- highlight .Inner $lang .Options -}}</div>
<div id="code-block-{{ .Ordinal }}">
{{- highlight .Inner $lang .Options -}}
</div>
{{- else -}}
<pre><code>{{ .Inner }}</code></pre>
<pre><code id="code-block-{{ .Ordinal }}">{{ .Inner }}</code></pre>
{{- 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="{{ $copyCode }}"
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>

View File

@ -1,13 +1,13 @@
{{- $alt := .PlainText | safeHTML -}}
{{- $lazyLoading := .Page.Site.Params.enableImageLazyLoading | default true -}}
{{- $lazyLoading := .Page.Site.Params.enableImagelazyLoading | default true -}}
{{- $dest := .Destination -}}
{{- $isLocal := not (urls.Parse $dest).Scheme -}}
{{- $isRemote := not (urls.Parse $dest).Scheme -}}
{{- $isPage := and (eq .Page.Kind "page") (not .Page.BundleType) -}}
{{- $startsWithSlash := hasPrefix $dest "/" -}}
{{- $startsWithRelative := hasPrefix $dest "../" -}}
{{- if and $dest $isLocal -}}
{{- if and $dest $isRemote -}}
{{- if $startsWithSlash -}}
{{/* Images under static directory */}}
{{- $dest = (relURL (strings.TrimPrefix "/" $dest)) -}}

View File

@ -1,12 +1,13 @@
<!DOCTYPE html>
<html lang="{{ .Site.Language.Lang }}">
{{- partial "head.html" . -}}
{{ partial "head.html" . -}}
<body dir="ltr">
{{- partial "navbar.html" . -}}
{{ partial "navbar.html" . -}}
{{- block "main" . }}{{ end -}}
{{- if or (eq .Site.Params.footer.enable nil) (.Site.Params.footer.enable) }}
{{ partial "footer.html" . }}
{{ end }}
{{ end -}}
</body>
{{ partial "scripts.html" . }}
{{ partialCached "scripts.html" . }}
{{ partial "third-party/scripts.html" . }}
</html>

View File

@ -1,6 +1,6 @@
{{ define "main" }}
{{- $readMore := (T "readMore") | default "Read more →" -}}
<div class="mx-auto flex {{ partial `utils/page-width` . }}">
{{- $readMore := (T "readMore") | default "Read more →" -}}
<div class='mx-auto flex {{ partial "utils/page-width" . }}'>
{{ 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)]">
<main class="w-full min-w-0 max-w-6xl px-6 pt-4 md:px-12">
@ -10,20 +10,11 @@
{{ range .Pages.ByDate.Reverse }}
<div class="mb-10">
<h3><a style="color: inherit; text-decoration: none;" class="block font-semibold mt-8 text-2xl " href="{{ .RelPermalink }}">{{ .Title }}</a></h3>
{{- if site.Params.blog.list.displayTags -}}
{{ with .Params.tags }}
<p class="opacity-50 text-sm leading-7">
{{- range . }}<a class="inline-block mr-2">#{{ . }}</a>{{ end -}}
</p>
{{ end -}}
{{- end -}}
<p class="opacity-80 mt-4 leading-7">{{- partial "utils/page-description" . -}}</p>
<p class="opacity-80 mt-1 leading-7">
<a class="text-[color:hsl(var(--primary-hue),100%,50%)] underline underline-offset-2 decoration-from-font" href="{{ .RelPermalink }}">
{{- $readMore -}}
</a>
<p class="opacity-80 mt-6 leading-7">
{{- 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 }}">{{ $readMore }}</a> </span>
</p>
<p class="opacity-50 text-sm mt-4 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>
{{ end }}
</main>

View File

@ -1,40 +1,27 @@
{{ define "main" }}
<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 "toc.html" . }}
<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)]">
<main class="w-full min-w-0 max-w-6xl px-6 pt-4 md:px-12">
{{ partial "breadcrumb.html" . }}
<h1 class="mt-2 text-4xl font-bold tracking-tight text-slate-900 dark:text-slate-100">{{ .Title }}</h1>
<div class="mt-4 mb-16 text-gray-500 text-sm flex items-center flex-wrap gap-y-2">
{{- with $date := .Date }}<span class="mr-1">{{ partial "utils/format-date" $date }}</span>{{ end -}}
{{- $lazyLoading := site.Params.enableImageLazyLoading | default true -}}
{{ if and .Date .Params.authors }}<span class="mx-1">·</span>{{ end -}}
{{- with $.Params.authors -}}
{{- range $i, $author := . -}}
{{- if reflect.IsMap $author -}}
{{- if and $i (not $author.image) }}<span class="mr-1">,</span>{{ end -}}
<a
{{ with $author.link }}href="{{ . }}" target="_blank"{{ end }}
class="group inline-flex items-center text-current gap-x-1.5 mx-1"
{{ with $author.name }}title="{{ . }}"{{ end }}
>
{{- with $image := $author.image }}
{{- $isLocal := not (urls.Parse $image).Scheme -}}
{{- $startsWithSlash := hasPrefix $image "/" -}}
{{- if and $isLocal $startsWithSlash }}
{{- $image = (relURL (strings.TrimPrefix "/" $image)) -}}
{{ end -}}
<img src="{{ $image | safeURL }}" alt="{{ $author.name }}" class="inline-block h-4 w-4 rounded-full" {{ if $lazyLoading }}loading="lazy"{{ end }} />
{{ end -}}
<div class="group-hover:underline">{{ $author.name }}</div>
</a>
{{- else -}}
{{- if $i }}<span class="mr-1">,</span>{{ end -}}<span class="mx-1">{{ $author }}</span>
{{ with $date := .Date }}
<div class="mt-4 mb-16 text-gray-500 text-sm">
{{ partial "utils/format-date" $date }}
{{- if $.Params.authors }}&nbsp;by&nbsp;{{ end -}}
{{- with $.Params.authors -}}
{{- range $i, $author := . -}}
{{- if $i }},{{ end -}}
{{- if $author.link -}}
<a href="{{ $author.link }}" target="_blank" class="mx-1 text-current underline [text-underline-position:from-font] decoration-from-font">{{ $author.name }}</a>
{{- else -}}
<span>{{ $author.name }}</span>
{{- end -}}
{{- end -}}
{{- end -}}
{{- end -}}
</div>
</div>
{{ end }}
<div class="content">
{{ .Content }}
</div>

View File

@ -2,7 +2,6 @@
{{- $displayThemeToggle := site.Params.theme.displayToggle | default true -}}
{{- $copyright := (T "copyright") | default "© 2023 Hextra." -}}
{{- $poweredBy := (T "poweredBy") | default "Powered by Hextra" -}}
{{- $footerWidth := "max-w-screen-xl" -}}
{{- with .Site.Params.footer.width -}}
@ -28,7 +27,7 @@
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">
{{- if (.Site.Params.footer.displayPoweredBy | default true) }}<div class="font-semibold">{{ template "theme-credit" $poweredBy }}</div>{{ end }}
{{- if (.Site.Params.footer.displayPoweredBy | default true) }}<div class="font-semibold">{{ template "theme-credit" . }}</div>{{ end }}
{{- if .Site.Params.footer.displayCopyright }}<div class="mt-6 text-xs">{{ $copyright | markdownify }}</div>{{ end }}
</div>
</div>
@ -36,11 +35,9 @@
{{- define "theme-credit" -}}
<a class="flex text-sm items-center gap-1 text-current" target="_blank" rel="noopener noreferrer" title="Hextra GitHub Homepage" href="https://github.com/imfing/hextra">
<span>
{{- . | markdownify -}}
{{- if strings.Contains . "Hextra" -}}
{{- partial "utils/icon.html" (dict "name" "hextra" "attributes" `height=1em class="inline-block ml-1 align-[-2.5px]"`) -}}
{{- end -}}
<span
>Powered by Hextra
{{- partial "utils/icon.html" (dict "name" "hextra" "attributes" "height=1em class=\"inline-block ml-1 align-text-bottom\"") -}}
</span>
</a>
{{- end -}}

View File

@ -1,10 +1,4 @@
{{/* site.GoogleAnalytics is deprecated in Hugo v0.120.0 */}}
{{/* it will be removed in a future version */}}
{{- $gtagID := "" -}}
{{- with site.GoogleAnalytics -}}{{ $gtagID = . }}{{- end -}}
{{- with site.Config.Services.GoogleAnalytics.ID -}}{{ $gtagID = . }}{{- end -}}
{{- with $gtagID }}
{{ with .Site.GoogleAnalytics }}
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id={{ . }}"></script>
<script>
@ -16,4 +10,4 @@
gtag("config", "{{ . }}");
</script>
{{ end -}}
{{ end }}

View File

@ -25,7 +25,7 @@
<!-- Google Analytics -->
{{- if and (eq hugo.Environment "production") (or .Site.GoogleAnalytics .Site.Config.Services.GoogleAnalytics.ID) }}
{{- if and .Site.GoogleAnalytics (eq hugo.Environment "production") }}
<link rel="preconnect" href="https://www.googletagmanager.com" crossorigin />
{{ partial "google-analytics.html" . }}
{{- end }}

View File

@ -30,20 +30,12 @@
{{- $currentPage := . -}}
{{- range .Site.Menus.main -}}
{{- if eq .Params.type "search" -}}
{{- partial "search.html" (dict "params" .Params) -}}
{{- partialCached "search.html" $currentPage -}}
{{- else -}}
{{- $link := .URL -}}
{{- $external := strings.HasPrefix $link "http" -}}
{{- with .PageRef -}}
{{- if hasPrefix . "/" -}}
{{- $link = relLangURL (strings.TrimPrefix "/" .) -}}
{{- end -}}
{{- end -}}
{{- $external := strings.HasPrefix .URL "http" -}}
{{/* Display icon menu item */}}
{{- if .Params.icon -}}
{{- $rel := cond (eq .Params.icon "mastodon") "noreferer me" "noreferer" }}
<a class="p-2 text-current" {{ if $external }}target="_blank" rel="{{ $rel }}"{{ end }} href="{{ $link }}" title="{{ or (T .Identifier) .Name | safeHTML }}">
<a class="p-2 text-current" {{ if $external }}target="_blank" rel="noreferer"{{ end }} href="{{ .URL | relLangURL }}" title="{{ or (T .Identifier) .Name | safeHTML }}">
{{- partial "utils/icon.html" (dict "name" .Params.icon "attributes" "height=24") -}}
<span class="sr-only">{{ or (T .Identifier) .Name | safeHTML }}</span>
</a>
@ -52,7 +44,7 @@
{{- $activeClass := cond $active "font-medium" "text-gray-600 hover:text-gray-800 dark:text-gray-400 dark:hover:text-gray-200" -}}
<a
title="{{ or (T .Identifier) .Name | safeHTML }}"
href="{{ $link }}"
href="{{ .URL | relLangURL }}"
{{ if $external }}target="_blank" rel="noreferer"{{ end }}
class="text-sm contrast-more:text-gray-700 contrast-more:dark:text-gray-100 relative -ml-2 hidden whitespace-nowrap p-2 md:inline-block {{ $activeClass }}"
>

View File

@ -27,49 +27,6 @@
<script defer src="{{ $flexSearchJS.RelPermalink }}" integrity="{{ $flexSearchJS.Data.Integrity }}"></script>
<script defer src="{{ $jsSearch.RelPermalink }}" integrity="{{ $jsSearch.Data.Integrity }}"></script>
{{- else -}}
{{- warnf `search type "%s" is not supported` $searchType -}}
{{- errorf `search type "%s" is not supported` $searchType -}}
{{- 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 }}

View File

@ -8,37 +8,58 @@
{{- $navRoot := cond (eq site.Home.Type "docs") site.Home $context.FirstSection -}}
{{- $pageURL := $context.RelPermalink -}}
{{/* EXPERIMENTAL */}}
{{- if .context.Params.sidebar.hide -}}
{{- $disableSidebar = true -}}
{{- $displayPlaceholder = true -}}
{{- end -}}
<div class="mobile-menu-overlay [transition:background-color_1.5s_ease] fixed inset-0 z-10 bg-black/80 dark:bg-black/60 hidden"></div>
<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 -->
<div class="px-4 pt-4 md:hidden">
{{ partial "search.html" }}
</div>
{{/* Search bar on small screen */}}
{{- partialCached "sidebar/mobile-search" . -}}
<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">
<!-- Nav -->
{{ template "sidebar-main" (dict "context" site.Home "pageURL" $pageURL "page" $context "toc" true) -}}
{{ template "sidebar-footer" }}
{{/* Mobile Navigation */}}
{{ $treeMobile := partialCached "sidebar/section-tree" site.Home site.Home }}
{{ partial "sidebar/render-tree" (dict "context" site.Home "page" $context "tree" ($treeMobile | unmarshal)) }}
{{ partialCached "sidebar/extra" $context }}
</ul>
<!-- Sidebar on large screen -->
{{- if $disableSidebar -}}
{{- if $displayPlaceholder }}<div class="max-xl:hidden h-0 w-64 shrink-0"></div>{{ end -}}
{{ .context.Scratch.Set "enableFooterSwitches" true }}
{{- else -}}
<ul class="flex flex-col gap-1 max-md:hidden">
{{ template "sidebar-main" (dict "context" $navRoot "page" $context "pageURL" $pageURL) }}
{{ template "sidebar-footer" }}
</ul>
{{ end -}}
{{/* Sidebar on large screen */}}
<ul class="flex flex-col gap-1 max-md:hidden">
{{ $tree := partialCached "sidebar/section-tree" $navRoot $navRoot }}
{{ partial "sidebar/render-tree" (dict "context" $navRoot "page" $context "tree" ($tree | unmarshal)) }}
{{ partialCached "sidebar/extra" $context }}
</ul>
</div>
{{ partial "sidebar/switches" (dict "context" $context "disableSidebar" $disableSidebar) }}
</aside>
{{- define "partials/sidebar/mobile-search" -}}
<div class="px-4 pt-4 md:hidden">
{{- partialCached "search.html" . -}}
</div>
{{- end -}}
{{- define "sidebar-item-link" -}}
{{- $external := strings.HasPrefix .link "http" -}}
<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]
{{- if .active }}
sidebar-active-item bg-primary-100 font-semibold text-primary-800 contrast-more:border contrast-more:border-primary-500 dark:bg-primary-400/10 dark:text-primary-600 contrast-more:dark:border-primary-500
{{- else }}
text-gray-500 hover:bg-gray-100 hover:text-gray-900 contrast-more:border contrast-more:border-transparent contrast-more:text-gray-900 contrast-more:hover:border-gray-900 dark:text-neutral-400 dark:hover:bg-primary-100/5 dark:hover:text-gray-50 contrast-more:dark:text-gray-50 contrast-more:dark:hover:border-gray-50
{{- end -}}"
href="{{ .link }}"
{{ if $external }}target="_blank" rel="noreferer"{{ end }}
>
{{- .title | htmlUnescape | safeHTML -}}
{{- with .context }}
{{- if or .RegularPages .Sections .section }}{{ partialCached "sidebar/collapsible-button" . }}{{ end -}}
{{ end -}}
</a>
{{- end -}}
{{- define "partials/sidebar/switches" -}}
{{- $context := .context -}}
{{- $disableSidebar := .disableSidebar -}}
{{/* Hide theme switch when sidebar is disabled */}}
{{ $switchesClass := cond $disableSidebar "md:hidden" "" -}}
{{ $displayThemeToggle := (site.Params.theme.displayToggle | default true) -}}
@ -55,123 +76,4 @@
{{- end -}}
</div>
{{- end -}}
</aside>
{{- define "sidebar-main" -}}
{{ template "sidebar-tree" (dict "context" .context "level" 0 "page" .page "pageURL" .pageURL "toc" (.toc | default false)) }}
{{- end -}}
{{- 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 -}}
{{- $items = where $items "Params.sidebar.exclude" "!=" true -}}
{{- if eq $level 0 -}}
{{- range $items.ByWeight }}
{{- if .Params.sidebar.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">{{ .LinkTitle }}</span>
</li>
{{- else -}}
{{- $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 -}}
{{- end -}}
{{- else -}}
<div class="ltr:pr-0 overflow-hidden">
<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 {{ 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 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 -}}
{{- define "sidebar-item-link" -}}
{{- $external := strings.HasPrefix .link "http" -}}
{{- $open := .open | default true -}}
<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]
{{- if .active }}
sidebar-active-item bg-primary-100 font-semibold text-primary-800 contrast-more:border contrast-more:border-primary-500 dark:bg-primary-400/10 dark:text-primary-600 contrast-more:dark:border-primary-500
{{- else }}
text-gray-500 hover:bg-gray-100 hover:text-gray-900 contrast-more:border contrast-more:border-transparent contrast-more:text-gray-900 contrast-more:hover:border-gray-900 dark:text-neutral-400 dark:hover:bg-primary-100/5 dark:hover:text-gray-50 contrast-more:dark:text-gray-50 contrast-more:dark:hover:border-gray-50
{{- end -}}"
href="{{ .link }}"
{{ if $external }}target="_blank" rel="noreferer"{{ end }}
>
{{- .title -}}
{{- with .context }}
{{- if or .RegularPages .Sections }}
<span class="hextra-sidebar-collapsible-button">
{{- template "sidebar-collapsible-button" -}}
</span>
{{- end }}
{{ end -}}
</a>
{{- end -}}
{{- define "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>
{{- end -}}

View 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>

View 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 -}}

View File

@ -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>

View 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>

View 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 }}

View 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)) }}

View 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 }}

View File

@ -1,8 +1,6 @@
{{- $hideLabel := .hideLabel | default false -}}
{{- $changeTheme := (T "changeTheme") | default "Change theme" -}}
{{- $light := (T "light") | default "Light" -}}
{{- $dark := (T "dark") | default "Dark" -}}
<button
@ -10,12 +8,12 @@
data-theme="light"
class="theme-toggle group h-7 rounded-md px-2 text-left text-xs font-medium text-gray-600 transition-colors dark:text-gray-400 hover:bg-gray-100 hover:text-gray-900 dark:hover:bg-primary-100/5 dark:hover:text-gray-50"
type="button"
aria-label="{{ $changeTheme }}"
aria-label="Toggle Dark Mode"
>
<div class="flex items-center gap-2 capitalize">
{{- partial "utils/icon.html" (dict "name" "sun" "attributes" "height=12 class=\"group-data-[theme=light]:hidden\"") -}}
{{- if not $hideLabel }}<span class="group-data-[theme=light]:hidden">{{ $light }}</span>{{ end -}}
{{- if not $hideLabel }}<span class="group-data-[theme=light]:hidden">Light</span>{{ end -}}
{{- partial "utils/icon.html" (dict "name" "moon" "attributes" "height=12 class=\"group-data-[theme=dark]:hidden\"") -}}
{{- if not $hideLabel }}<span class="group-data-[theme=dark]:hidden">{{ $dark }}</span>{{ end -}}
{{- if not $hideLabel }}<span class="group-data-[theme=dark]:hidden">Dark</span>{{ end -}}
</div>
</button>

View 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 }}

View File

@ -27,7 +27,7 @@
{{- if site.Params.editURL.enable -}}
{{- $editURL := site.Params.editURL.base | default "" -}}
{{- with .File -}}{{ $editURL = urls.JoinPath $editURL (replace .Path "\\" "/") }}{{- end -}}
{{- with .Params.editURL -}}{{ $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>
{{- end -}}
{{/* Scroll To Top */}}
@ -59,7 +59,7 @@
{{- if .Title }}
<li class="my-2 scroll-my-6 scroll-py-6">
<a class="{{ $class }} inline-block text-gray-500 hover:text-gray-900 dark:text-gray-400 dark:hover:text-gray-300 contrast-more:text-gray-900 contrast-more:underline contrast-more:dark:text-gray-50 w-full break-words" href="#{{ anchorize .ID }}">
{{- .Title | safeHTML | plainify | htmlUnescape }}
{{- .Title | safeHTML }}
</a>
</li>
{{- end -}}

View File

@ -35,12 +35,12 @@
{{ $headingTitle := index $headingTitles $i }}
{{ if eq $i 0 }}
{{ $data = $data | merge (dict $headingKey ($content | $page.RenderString | plainify | htmlUnescape | chomp)) }}
{{ $data = $data | merge (dict $headingKey ($content | markdownify | plainify | htmlUnescape | chomp)) }}
{{ else }}
{{ $parts := split $content (printf "\n%s\n" $headingTitle) }}
{{ $lastPart := index $parts (sub (len $parts) 1) }}
{{ $data = $data | merge (dict $headingKey ($lastPart | $page.RenderString | plainify | htmlUnescape | chomp)) }}
{{ $data = $data | merge (dict $headingKey ($lastPart | markdownify | plainify | htmlUnescape | chomp)) }}
{{ $content = strings.TrimSuffix $lastPart $content }}
{{ $content = strings.TrimSuffix (printf "\n%s\n" $headingTitle) $content }}
{{ end }}

View File

@ -5,30 +5,17 @@
{{ if eq $emoji "" }}
{{ $emoji = index $calloutEmojiDict $type }}
{{ end }}
{{/* Also allow using "icon" */}}
{{ $icon := .Get "icon" }}
{{ $defaultClass := "border-orange-100 bg-orange-50 text-orange-800 dark:border-orange-400/30 dark:bg-orange-400/20 dark:text-orange-300" }}
{{ $infoClass := "border-blue-200 bg-blue-100 text-blue-900 dark:border-blue-200/30 dark:bg-blue-900/30 dark:text-blue-200" }}
{{ $warningClass := "border-yellow-100 bg-yellow-50 text-yellow-900 dark:border-yellow-200/30 dark:bg-yellow-700/30 dark:text-yellow-200" }}
{{ $errorClass := "border-red-200 bg-red-100 text-red-900 dark:border-red-200/30 dark:bg-red-900/30 dark:text-red-200" }}
{{ $class := cond (eq $type "info") $infoClass (cond (eq $type "warning") $warningClass (cond (eq $type "error") $errorClass $defaultClass)) }}
<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="ltr:pl-3 ltr:pr-2 rtl:pr-3 rtl:pl-2">
{{- with $emoji -}}
<div class="select-none text-xl" style="font-family: 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';">
{{ . }}
</div>
{{- else -}}
{{- with $icon }}
{{ partial "utils/icon.html" (dict "name" . "attributes" `height=1.2em class="inline-block align-middle"`) -}}
{{- end -}}
{{- end -}}
</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="mt-6 leading-7 first:mt-0">
{{ .Inner | markdownify }}

View File

@ -49,8 +49,9 @@
<a
class="hextra-card group flex flex-col justify-start overflow-hidden rounded-lg border border-gray-200 text-current no-underline dark:shadow-none hover:shadow-gray-100 dark:hover:shadow-none shadow-gray-100 active:shadow-sm active:shadow-gray-200 transition-all duration-200 {{ $linkClass }}"
{{- if $link -}}
href="{{ $href }}" {{ with $external }}target="_blank" rel="noreferrer"{{ end -}}
href="{{ $href }}"
{{- if $external }}
target="_blank" rel="noreferrer"
{{- end -}}
>
{{- with $image -}}
@ -79,4 +80,3 @@
<div class="line-clamp-3 text-sm font-normal text-gray-500 dark:text-gray-400 px-4 mb-4 mt-2">{{- $subtitle | markdownify -}}</div>
{{- end -}}
</a>
{{- /* Strip trailing newline. */ -}}

View File

@ -1,5 +1,5 @@
{{ $rows := .Get "rows" | default "3" }}
<div class="hextra-cards mt-4 gap-4 grid not-prose" style="--rows: {{ $rows }};">
{{- .Inner -}}
{{ .Inner }}
</div>

View File

@ -5,19 +5,11 @@
{{- $imageClass := .Get "imageClass" -}}
{{- $style := .Get "style" -}}
{{- $icon := .Get "icon" -}}
{{- $link := .Get "link" -}}
{{- $external := hasPrefix $link "http" -}}
{{- $href := cond (strings.HasPrefix $link "/") ($link | relURL) $link -}}
{{- if hasPrefix $image "/" -}}
{{- $image = relURL (strings.TrimPrefix "/" $image) -}}
{{- end -}}
<a
{{ with $link }}href="{{ $href }}" {{ with $external }} target="_blank" rel="noreferrer"{{ end }}{{ end }}
<div
{{ with $style }}style="{{ . | safeCSS }}"{{ end }}
class="{{ $class }} hextra-feature-card not-prose block relative overflow-hidden rounded-3xl border border-gray-200 hover:border-gray-300 dark:border-neutral-800 dark:hover:border-neutral-700 before:pointer-events-none before:absolute before:inset-0 before:bg-glass-gradient"
class="{{ $class }} hextra-feature-card relative overflow-hidden rounded-3xl border border-gray-200 hover:border-gray-300 dark:border-neutral-800 dark:hover:border-neutral-700 before:pointer-events-none before:absolute before:inset-0 before:bg-glass-gradient"
>
<div class="relative w-full p-6">
<h3 class="text-2xl font-medium leading-6 mb-2 flex items-center">
@ -33,4 +25,4 @@
{{- with $image -}}
<img src="{{ . }}" class="absolute max-w-none {{ $imageClass }}" alt="{{ $title }}" />
{{- end -}}
</a>
</div>

View File

@ -2,7 +2,7 @@
<div
class="grid sm:grid-cols-2 lg:grid-cols-3 grid-cols-1 gap-4 w-full not-prose"
class="grid sm:grid-cols-2 lg:grid-cols-3 grid-cols-1 gap-4 w-full"
{{ with $style }}style="{{ . | safeCSS }}"{{ end }}
>
{{ .Inner }}

View File

@ -6,8 +6,8 @@
<a
{{ if $link }}href="{{ $href }}"{{ end }}
class="{{ $class }} not-prose inline-flex items-center rounded-full gap-2 px-3 py-1 text-xs text-gray-600 dark:text-gray-400 bg-gray-100 dark:bg-neutral-800 dark:border-neutral-800 border hover:border-gray-400 dark:hover:text-gray-50 dark:hover:border-gray-600 transition-all ease-in duration-200"
href="{{ $href }}"
class="{{ $class }} inline-flex items-center rounded-full gap-2 px-3 py-1 text-xs text-gray-600 dark:text-gray-400 bg-gray-100 dark:bg-neutral-800 dark:border-neutral-800 border hover:border-gray-400 dark:hover:text-gray-50 dark:hover:border-gray-600 transition-all ease-in duration-200"
{{ with $style }}style="{{ . | safeCSS }}"{{ end }}
{{ if $external }}target="_blank" rel="noreferrer"{{ end -}}
>

View File

@ -7,7 +7,7 @@
<a
href="{{ $href }}"
class="not-prose font-medium cursor-pointer px-6 py-3 rounded-full text-center text-white inline-block bg-primary-600 hover:bg-primary-700 focus:outline-none focus:ring-4 focus:ring-primary-300 dark:bg-primary-600 dark:hover:bg-primary-700 dark:focus:ring-primary-800 transition-all ease-in duration-200"
class="font-medium cursor-pointer px-6 py-3 rounded-full text-center text-white inline-block bg-primary-600 hover:bg-primary-700 focus:outline-none focus:ring-4 focus:ring-primary-300 dark:bg-primary-600 dark:hover:bg-primary-700 dark:focus:ring-primary-800 transition-all ease-in duration-200"
{{ with $style }}style="{{ . | safeCSS }}"{{ end }}
{{ if $external }}target="_blank" rel="noreferrer"{{ end -}}
>

View File

@ -2,7 +2,7 @@
<h1
class="not-prose text-4xl font-bold leading-none tracking-tighter md:text-5xl py-2 bg-clip-text text-transparent bg-gradient-to-r from-gray-900 to-gray-600 dark:from-gray-100 dark:to-gray-400"
class="text-4xl font-bold leading-none tracking-tighter md:text-5xl py-2 bg-clip-text text-transparent bg-gradient-to-r from-gray-900 to-gray-600 dark:from-gray-100 dark:to-gray-400"
{{ with $style }}style="{{ . | safeCSS }}"{{ end }}
>
{{ .Inner | markdownify }}

View File

@ -2,7 +2,7 @@
<p
class="not-prose text-xl text-gray-600 dark:text-gray-400 sm:text-xl"
class="text-xl text-gray-600 dark:text-gray-400 sm:text-xl"
{{ with $style }}style="{{ . | safeCSS }}"{{ end }}
>
{{ .Inner | markdownify }}

View File

@ -1,22 +0,0 @@
{{- /*
https://github.com/gohugoio/gohugoioTheme/blob/master/layouts/shortcodes/include.html
Renders the page using the RenderShortcode method on the Page object.
You must call this shortcode using the {{% %}} notation.
@param {string} (postional parameter 0) The path to the page, relative to the content directory.
@returns template.HTML
@example {{% include "functions/_common/glob-patterns" %}}
*/}}
{{- with .Get 0 }}
{{- with site.GetPage . }}
{{- .RenderShortcodes }}
{{- else }}
{{- errorf "The %q shortcode was unable to find %q. See %s" $.Name . $.Position }}
{{- end }}
{{- else }}
{{- errorf "The %q shortcode requires a positional parameter indicating the path of the file to include. See %s" .Name .Position }}
{{- end }}

8
package-lock.json generated
View File

@ -7,7 +7,7 @@
"devDependencies": {
"@tailwindcss/nesting": "^0.0.0-insiders.565cd3e",
"autoprefixer": "^10.4.14",
"postcss": "^8.4.31",
"postcss": "^8.4.23",
"postcss-cli": "^10.1.0",
"postcss-import": "^15.1.0",
"prettier": "^2.8.8",
@ -958,9 +958,9 @@
}
},
"node_modules/postcss": {
"version": "8.4.31",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
"integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
"version": "8.4.27",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.27.tgz",
"integrity": "sha512-gY/ACJtJPSmUFPDCHtX78+01fHa64FaU4zaaWfuh1MhGJISufJAH4cun6k/8fwsHYeK4UQmENQK+tRLCFJE8JQ==",
"dev": true,
"funding": [
{

View File

@ -3,12 +3,13 @@
"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",
"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": {
"@tailwindcss/nesting": "^0.0.0-insiders.565cd3e",
"autoprefixer": "^10.4.14",
"postcss": "^8.4.31",
"postcss": "^8.4.23",
"postcss-cli": "^10.1.0",
"postcss-import": "^15.1.0",
"prettier": "^2.8.8",