Compare commits

..

49 Commits

Author SHA1 Message Date
Xin
f8e02e6151 fix: generate mobile nav data 2024-12-30 22:38:28 +00:00
Xin
b01c8ee405 chore: add example sidebar data file
- update docs
- replace original sidebar template with new sidebar template
- update references names
2024-12-29 00:33:09 +00:00
Xin
2acfb3b877 chore: test new sidebar rendering 2024-12-28 18:06:15 +00:00
Xin
4d9015aefe fix: replace deprecated site.IsMultiLingual 2024-12-28 17:55:55 +00:00
Xin
783ab1e97f Merge remote-tracking branch 'origin/main' into sidebar-data-source 2024-12-28 16:43:20 +00:00
Xin
12815aaddc docs: documentation updates for alerts and syntax highlighting 2024-12-28 16:23:58 +00:00
Xin
e532637cbc fix: correct tabs button color on hover in dark mode (#526)
* fix: tabs toggle button color in dark mode

* chore: update css
2024-12-28 15:51:35 +00:00
Xin
79bb4504a0 feat: add support for icon in badge shortcode (#525)
* feat: add icon support to badge shortcodes

- Introduced an optional icon parameter to both badge.html files.
- Updated the badge rendering to include the icon alongside the content.
- Enhanced the layout for better alignment of icon and text.

* feat: add new feature shortcode

* docs: update badge doc
2024-12-28 13:50:22 +00:00
26a298da5d feat: support link in code block title (#523)
* feat: support link in code block title

* refactor: simplify code block filename link implementation

* docs: update syntax-highlighting.md

* chore: rename `filename_uri_base` to `base_url`

[skip ci]

* refactor: use `base_url` int code block implementation

---------

Co-authored-by: Xin <xin@imfing.com>
2024-12-28 12:41:23 +00:00
Xin
cf61e606c1 docs: update customization instructions for footer section 2024-12-26 23:50:18 +00:00
0716533699 feat: add giscus theme customization (#522)
Co-authored-by: Xin <xin@imfing.com>
2024-12-26 12:29:21 +00:00
9efcda2fdd feat: support custom footer section (#518)
* Add support for custom footer

* amend how the custom footer section is displayed

* Add missing class

* add missing class

* Remove context variable and flag in hugo.yaml

* update hugo_stats

* Only show footer section for copyright and PoweredBy if they are enabled

* Add missing compiled css

* Added necessary variables for correct styling of the custom footer in some cases

* make padding consistent for copyright section and custom footer

* chore: update css

* chore: clean up css

* docs: update customization instructions

* fix: footer padding

---------

Co-authored-by: Xin <xin@imfing.com>
2024-12-25 21:25:47 +00:00
655148f329 docs: add advanced theme customization instruction (#519)
Some checks failed
Deploy Hugo site to Pages / build (push) Has been cancelled
Deploy Hugo site to Pages / deploy (push) Has been cancelled
* Add docs on how to customize theme

* fix heading level

* extend description

* Add missing classes

* Update exampleSite/content/docs/advanced/customization.md

---------

Co-authored-by: Xin <fuxin1997@gmail.com>
2024-12-18 22:48:42 +00:00
Xin
b6d14afca3 docs(showcase): update link for lutheran-confessions
fixes #520
2024-12-18 22:35:52 +00:00
bc778ee243 fix: only display footer switches section if it actually has content (#517)
Some checks failed
Deploy Hugo site to Pages / build (push) Has been cancelled
Deploy Hugo site to Pages / deploy (push) Has been cancelled
2024-12-16 22:21:15 +00:00
Xin
f377609eba docs: update HUGO_VERSION to 0.138.0 in deployment documentation
Some checks are pending
Deploy Hugo site to Pages / build (push) Waiting to run
Deploy Hugo site to Pages / deploy (push) Blocked by required conditions
2024-12-15 20:32:54 +00:00
Xin
a9b992436e chore: update HUGO_VERSION to 0.138.0 in GitHub Actions workflow
* add FUNDING.yml
2024-12-15 20:26:11 +00:00
7f5a7f2f5a chore(deps-dev): bump cross-spawn from 7.0.3 to 7.0.6 (#515) 2024-12-15 16:33:44 +00:00
30fddec3fa chore(deps): bump nanoid from 3.3.7 to 3.3.8 (#514)
Some checks are pending
Deploy Hugo site to Pages / build (push) Waiting to run
Deploy Hugo site to Pages / deploy (push) Blocked by required conditions
2024-12-15 14:20:52 +00:00
Xin
68dd327312 feat: support github style alerts (#513)
Some checks are pending
Deploy Hugo site to Pages / build (push) Waiting to run
Deploy Hugo site to Pages / deploy (push) Blocked by required conditions
* feat: basic github style alerts support

* feat: implement github style alert

* chore: re-generate css

* chore: add missing prettier config

* docs: add alerts instructions to markdown

* chore: revert "docs: add alerts instructions to markdown"

This reverts commit 3a70540e0b.

* chore: redo "docs: add alerts instructions to markdown""

This reverts commit 8399373747.

* chore(build): bump hugo version
2024-12-14 23:44:10 +00:00
0c90c1aa50 feat: add hextra hero-section shortcode (#390)
Some checks failed
Deploy Hugo site to Pages / build (push) Has been cancelled
Deploy Hugo site to Pages / deploy (push) Has been cancelled
* Implement hextra hero-section

* Implement header size

* Update layouts/shortcodes/hextra/hero-section.html

* Update layouts/shortcodes/hextra/hero-section.html

* Update layouts/shortcodes/hextra/hero-section.html

* Update layouts/shortcodes/hextra/hero-section.html

---------

Co-authored-by: Xin <fuxin1997@gmail.com>
2024-12-10 23:58:36 +00:00
Xin
fe2271b60b docs(showcase): add "Model Context Protocol Specification"
Some checks failed
Deploy Hugo site to Pages / build (push) Has been cancelled
Deploy Hugo site to Pages / deploy (push) Has been cancelled
2024-12-08 12:38:44 +00:00
bd34a5bad3 fix: rerender mermaid diagrams on theme change (#509)
Make mermaid render diagrams on manual toggle between themes, after initial page load
2024-12-08 12:29:28 +00:00
0dcf7e7a40 chore(icons): add bluesky icon (#505)
Some checks failed
Deploy Hugo site to Pages / build (push) Has been cancelled
Deploy Hugo site to Pages / deploy (push) Has been cancelled
* Update icons.yaml to add bsky icon

Added BlueSky icon to socials

* update the fill color to current color

* Update data/icons.yaml

---------

Co-authored-by: Xin <fuxin1997@gmail.com>
2024-12-04 07:34:02 +00:00
86a1f3fd96 docs(showcase): add cellular_raza (#498)
Some checks failed
Deploy Hugo site to Pages / build (push) Has been cancelled
Deploy Hugo site to Pages / deploy (push) Has been cancelled
* add cellular_raza to showcase exampleSite

* use link from github PR to store image

Co-authored-by: Xin <fuxin1997@gmail.com>

---------

Co-authored-by: Xin <fuxin1997@gmail.com>
2024-11-14 11:18:59 +00:00
Xin
168ecf91f4 Merge remote-tracking branch 'origin/main' into sidebar-data-source 2024-11-11 22:59:41 +00:00
Xin
4c4f43779c build(ci): build doc site from latest release instead of main
Some checks failed
Deploy Hugo site to Pages / build (push) Has been cancelled
Deploy Hugo site to Pages / deploy (push) Has been cancelled
- bump hugo version in workflow
- bump github actions deps versions
- minor update to head.html to remove empty spaces
2024-11-03 16:53:18 +00:00
Xin
ff85e6951d chore: update bug report template 2024-11-03 16:08:29 +00:00
Xin
ec37876f4d docs(showcase): add Sidekick 2024-11-03 15:35:32 +00:00
f65aca556d fix: typo in ref="noreferrer" (#489)
Some checks failed
Deploy Hugo site to Pages / build (push) Has been cancelled
Deploy Hugo site to Pages / deploy (push) Has been cancelled
2024-11-01 10:12:14 +00:00
Xin
9e7b13a0da chore: add experimental flag for hiding sidebar 2024-05-01 00:02:05 +01:00
Xin
66489e5274 chore: use index as fallback option 2024-04-30 23:56:57 +01:00
Xin
2004648076 fix: class name in render-data 2024-04-30 23:54:06 +01:00
Xin
0da6f97e99 fix: pass in the right page link 2024-04-30 23:03:09 +01:00
Xin
a4bfa2d97e chore: use utils/title to get title 2024-04-30 23:02:36 +01:00
Xin
3a2ce0b5c0 fix: class selector in sidebar.js 2024-04-30 22:44:09 +01:00
Xin
55af474f51 chore: update sidebar item list and link class names 2024-04-30 22:42:04 +01:00
Xin
b91cc79674 Merge remote-tracking branch 'origin/main' into sidebar-data-source 2024-04-30 08:58:06 +01:00
Xin
68e1e25119 feat: caching for sidebar items from data 2024-04-29 22:36:48 +01:00
Xin
8c789626be refactor: move sidebar item styles to css 2024-04-28 23:37:50 +01:00
Xin
a1c7acd6b5 feat: add params page.sidebar.source and page.sidebar.cache 2024-04-14 23:53:53 +01:00
Xin
e444156bb9 refactor: add back mobile and footer for sidebar 2024-04-14 12:28:39 +01:00
Xin
33f2cf653b feat: generate sidebar json data for rendering 2024-04-14 11:31:13 +01:00
Xin
63f153999e chore: basic rendering from data 2024-04-14 11:12:17 +01:00
Xin
c62b1fd401 refactor: make sidebar footer work 2024-04-14 10:23:52 +01:00
Xin
fdfdef69b5 chore: basic structure using new sidebar data 2024-04-05 21:30:24 +01:00
Xin
462cc5b68d chore: add new sidebar template 2024-04-04 21:57:17 +00:00
Xin
f40c7fd5d4 Merge remote-tracking branch 'origin/main' into sidebar-data-source 2024-04-04 20:39:47 +00:00
Xin
74fb165358 feat: sidebar util to read data 2024-04-03 22:36:58 +00:00
53 changed files with 1105 additions and 350 deletions

15
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1,15 @@
# These are supported funding model platforms
github: imfing
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
polar: # Replace with a single Polar username
buy_me_a_coffee: # Replace with a single Buy Me a Coffee username
thanks_dev: # Replace with a single thanks.dev username
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

View File

@ -17,6 +17,8 @@ assignees: ''
2.
3.
<!-- Provide a minimal example or link to a repository that reproduces the bug -->
**Expected Behavior**
<!-- What should have happened? -->

View File

@ -31,7 +31,7 @@ jobs:
build:
runs-on: ubuntu-latest
env:
HUGO_VERSION: 0.131.0
HUGO_VERSION: 0.138.0
steps:
- name: Checkout
uses: actions/checkout@v4
@ -41,10 +41,10 @@ jobs:
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: '1.22'
go-version: '1.23'
- name: Setup Pages
id: pages
uses: actions/configure-pages@v4
uses: actions/configure-pages@v5
- name: Setup Hugo
run: |
wget -O ${{ runner.temp }}/hugo.deb https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-amd64.deb \
@ -54,11 +54,12 @@ jobs:
# For maximum backward compatibility with Hugo modules
HUGO_ENVIRONMENT: production
HUGO_ENV: production
# Use the latest release of the theme to build exampleSite
run: |
hugo \
--minify \
--themesDir=../.. --source=exampleSite \
--baseURL "${{ steps.pages.outputs.base_url }}/"
cd exampleSite && rm go.mod
hugo mod init github.com/imfing/hextra/exampleSite
hugo mod get -u github.com/imfing/hextra
hugo --minify --baseURL "${{ steps.pages.outputs.base_url }}/"
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:

View File

@ -1,4 +1,7 @@
{
"plugins": [
"prettier-plugin-go-template"
],
"goTemplateBracketSpacing": true,
"htmlWhitespaceSensitivity": "css",
"printWidth": 200,

View File

@ -860,9 +860,6 @@ video {
.hx-justify-center {
justify-content: center;
}
.hx-justify-between {
justify-content: space-between;
}
.hx-justify-items-start {
justify-items: start;
}
@ -952,6 +949,10 @@ video {
.hx-border-t {
border-top-width: 1px;
}
.hx-border-amber-200 {
--tw-border-opacity: 1;
border-color: rgb(253 230 138 / var(--tw-border-opacity));
}
.hx-border-black\/5 {
border-color: rgb(0 0 0 / 0.05);
}
@ -967,6 +968,14 @@ video {
--tw-border-opacity: 1;
border-color: rgb(107 114 128 / var(--tw-border-opacity));
}
.hx-border-green-200 {
--tw-border-opacity: 1;
border-color: rgb(187 247 208 / var(--tw-border-opacity));
}
.hx-border-indigo-200 {
--tw-border-opacity: 1;
border-color: rgb(199 210 254 / var(--tw-border-opacity));
}
.hx-border-orange-100 {
--tw-border-opacity: 1;
border-color: rgb(255 237 213 / var(--tw-border-opacity));
@ -982,6 +991,10 @@ video {
--tw-border-opacity: 1;
border-color: rgb(254 249 195 / var(--tw-border-opacity));
}
.hx-bg-amber-100 {
--tw-bg-opacity: 1;
background-color: rgb(254 243 199 / var(--tw-bg-opacity));
}
.hx-bg-black\/80 {
background-color: rgb(0 0 0 / 0.8);
}
@ -996,6 +1009,14 @@ video {
--tw-bg-opacity: 1;
background-color: rgb(243 244 246 / var(--tw-bg-opacity));
}
.hx-bg-green-100 {
--tw-bg-opacity: 1;
background-color: rgb(220 252 231 / var(--tw-bg-opacity));
}
.hx-bg-indigo-100 {
--tw-bg-opacity: 1;
background-color: rgb(224 231 255 / var(--tw-bg-opacity));
}
.hx-bg-neutral-50 {
--tw-bg-opacity: 1;
background-color: rgb(250 250 250 / var(--tw-bg-opacity));
@ -1004,10 +1025,6 @@ video {
--tw-bg-opacity: 1;
background-color: rgb(255 247 237 / var(--tw-bg-opacity));
}
.hx-bg-primary-100 {
--tw-bg-opacity: 1;
background-color: hsl(var(--primary-hue) var(--primary-saturation) calc(var(--primary-lightness) + calc(calc(100% - var(--primary-lightness)) / 50) * 44) / var(--tw-bg-opacity));
}
.hx-bg-primary-400 {
--tw-bg-opacity: 1;
background-color: hsl(var(--primary-hue) var(--primary-saturation) calc(var(--primary-lightness) + calc(calc(100% - var(--primary-lightness)) / 50) * 16) / var(--tw-bg-opacity));
@ -1161,6 +1178,9 @@ video {
.hx-text-center {
text-align: center;
}
.hx-align-middle {
vertical-align: middle;
}
.hx-align-text-bottom {
vertical-align: text-bottom;
}
@ -1237,6 +1257,10 @@ video {
--tw-text-opacity: 1;
color: hsl(var(--primary-hue) 100% 50% / var(--tw-text-opacity));
}
.hx-text-amber-900 {
--tw-text-opacity: 1;
color: rgb(120 53 15 / var(--tw-text-opacity));
}
.hx-text-blue-900 {
--tw-text-opacity: 1;
color: rgb(30 58 138 / var(--tw-text-opacity));
@ -1268,14 +1292,18 @@ video {
--tw-text-opacity: 1;
color: rgb(17 24 39 / var(--tw-text-opacity));
}
.hx-text-green-900 {
--tw-text-opacity: 1;
color: rgb(20 83 45 / var(--tw-text-opacity));
}
.hx-text-indigo-900 {
--tw-text-opacity: 1;
color: rgb(49 46 129 / var(--tw-text-opacity));
}
.hx-text-orange-800 {
--tw-text-opacity: 1;
color: rgb(154 52 18 / var(--tw-text-opacity));
}
.hx-text-primary-800 {
--tw-text-opacity: 1;
color: hsl(var(--primary-hue) var(--primary-saturation) calc(calc(var(--primary-lightness) / 50) * 32) / var(--tw-text-opacity));
}
.hx-text-red-900 {
--tw-text-opacity: 1;
color: rgb(127 29 29 / var(--tw-text-opacity));
@ -2444,7 +2472,7 @@ article details > summary::before {
color: hsl(var(--primary-hue) var(--primary-saturation) calc(calc(var(--primary-lightness) / 50) * 45) / var(--tw-text-opacity));
}
@media (max-width: 767px) {
.sidebar-container {
.hextra-sidebar-container {
position: fixed;
top: 0px;
bottom: 0px;
@ -2455,28 +2483,152 @@ article details > summary::before {
background-color: rgb(255 255 255 / var(--tw-bg-opacity));
padding-top: calc(var(--navbar-height));
}
.sidebar-container:is(html[class~="dark"] *) {
.hextra-sidebar-container:is(html[class~="dark"] *) {
--tw-bg-opacity: 1;
background-color: rgb(17 17 17 / var(--tw-bg-opacity));
}
.sidebar-container {
.hextra-sidebar-container {
transition: transform 0.8s cubic-bezier(0.52, 0.16, 0.04, 1);
will-change: transform, opacity;
contain: layout style;
backface-visibility: hidden;
}
}
.sidebar-container li > div {
.hextra-sidebar-container li > div {
height: 0px;
}
.sidebar-container li.open > div {
.hextra-sidebar-container li.open > div {
height: auto;
padding-top: 0.25rem;
}
.sidebar-container li.open > a > span > svg > path {
.hextra-sidebar-container li.open > a > span > svg > path {
--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));
}
.hextra-sidebar-container .hextra-sidebar-item-list {
position: relative;
display: flex;
flex-direction: column;
gap: 0.25rem;
}
.hextra-sidebar-container .hextra-sidebar-item-list::before {
position: absolute;
top: 0.25rem;
bottom: 0.25rem;
width: 1px;
content: var(--tw-content);
--tw-bg-opacity: 1;
background-color: rgb(229 231 235 / var(--tw-bg-opacity));
}
.hextra-sidebar-container .hextra-sidebar-item-list:is(html[class~="dark"] *)::before {
content: var(--tw-content);
--tw-bg-opacity: 1;
background-color: rgb(38 38 38 / var(--tw-bg-opacity));
}
.hextra-sidebar-container .hextra-sidebar-item-list:where([dir="ltr"], [dir="ltr"] *) {
margin-left: 0.75rem;
padding-left: 0.75rem;
}
.hextra-sidebar-container .hextra-sidebar-item-list:where([dir="ltr"], [dir="ltr"] *)::before {
content: var(--tw-content);
left: 0px;
}
.hextra-sidebar-container .hextra-sidebar-item-list:where([dir="rtl"], [dir="rtl"] *) {
margin-right: 0.75rem;
padding-right: 0.75rem;
}
.hextra-sidebar-container .hextra-sidebar-item-list:where([dir="rtl"], [dir="rtl"] *)::before {
content: var(--tw-content);
right: 0px;
}
.hextra-sidebar-container .hextra-sidebar-item-link {
display: flex;
cursor: pointer;
align-items: center;
justify-content: space-between;
gap: 0.5rem;
border-radius: 0.25rem;
padding-left: 0.5rem;
padding-right: 0.5rem;
padding-top: 0.375rem;
padding-bottom: 0.375rem;
font-size: .875rem;
transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-duration: 150ms;
}
.hextra-sidebar-container .hextra-sidebar-item-link.active {
--tw-bg-opacity: 1;
background-color: hsl(var(--primary-hue) var(--primary-saturation) calc(var(--primary-lightness) + calc(calc(100% - var(--primary-lightness)) / 50) * 44) / var(--tw-bg-opacity));
font-weight: 600;
--tw-text-opacity: 1;
color: hsl(var(--primary-hue) var(--primary-saturation) calc(calc(var(--primary-lightness) / 50) * 32) / var(--tw-text-opacity));
}
@media (prefers-contrast: more) {
.hextra-sidebar-container .hextra-sidebar-item-link.active {
border-width: 1px;
--tw-border-opacity: 1;
border-color: hsl(var(--primary-hue) var(--primary-saturation) calc(calc(var(--primary-lightness) / 50) * 50) / var(--tw-border-opacity));
}
}
.hextra-sidebar-container .hextra-sidebar-item-link.active:is(html[class~="dark"] *) {
background-color: hsl(var(--primary-hue) var(--primary-saturation) calc(var(--primary-lightness) + calc(calc(100% - var(--primary-lightness)) / 50) * 16) / 0.1);
--tw-text-opacity: 1;
color: hsl(var(--primary-hue) var(--primary-saturation) calc(calc(var(--primary-lightness) / 50) * 45) / var(--tw-text-opacity));
}
@media (prefers-contrast: more) {
.hextra-sidebar-container .hextra-sidebar-item-link.active:is(html[class~="dark"] *) {
--tw-border-opacity: 1;
border-color: hsl(var(--primary-hue) var(--primary-saturation) calc(calc(var(--primary-lightness) / 50) * 50) / var(--tw-border-opacity));
}
}
.hextra-sidebar-container .hextra-sidebar-item-link.inactive {
--tw-text-opacity: 1;
color: rgb(107 114 128 / var(--tw-text-opacity));
}
.hextra-sidebar-container .hextra-sidebar-item-link.inactive:hover {
--tw-bg-opacity: 1;
background-color: rgb(243 244 246 / var(--tw-bg-opacity));
--tw-text-opacity: 1;
color: rgb(17 24 39 / var(--tw-text-opacity));
}
@media (prefers-contrast: more) {
.hextra-sidebar-container .hextra-sidebar-item-link.inactive {
border-width: 1px;
border-color: transparent;
--tw-text-opacity: 1;
color: rgb(17 24 39 / var(--tw-text-opacity));
}
.hextra-sidebar-container .hextra-sidebar-item-link.inactive:hover {
--tw-border-opacity: 1;
border-color: rgb(17 24 39 / var(--tw-border-opacity));
}
}
.hextra-sidebar-container .hextra-sidebar-item-link.inactive:is(html[class~="dark"] *) {
--tw-text-opacity: 1;
color: rgb(163 163 163 / var(--tw-text-opacity));
}
.hextra-sidebar-container .hextra-sidebar-item-link.inactive:hover:is(html[class~="dark"] *) {
background-color: hsl(var(--primary-hue) var(--primary-saturation) calc(var(--primary-lightness) + calc(calc(100% - var(--primary-lightness)) / 50) * 44) / 0.05);
--tw-text-opacity: 1;
color: rgb(249 250 251 / var(--tw-text-opacity));
}
@media (prefers-contrast: more) {
.hextra-sidebar-container .hextra-sidebar-item-link.inactive:is(html[class~="dark"] *) {
--tw-text-opacity: 1;
color: rgb(249 250 251 / var(--tw-text-opacity));
}
.hextra-sidebar-container .hextra-sidebar-item-link.inactive:hover:is(html[class~="dark"] *) {
--tw-border-opacity: 1;
border-color: rgb(249 250 251 / var(--tw-border-opacity));
}
}
nav .search-wrapper {
display: none;
}
@ -2650,11 +2802,6 @@ body:is(html[class~="dark"] *) {
content: var(--tw-content);
inset: 0px;
}
.before\:hx-inset-y-1::before {
content: var(--tw-content);
top: 0.25rem;
bottom: 0.25rem;
}
.before\:hx-mr-1::before {
content: var(--tw-content);
margin-right: 0.25rem;
@ -2663,37 +2810,16 @@ body:is(html[class~="dark"] *) {
content: var(--tw-content);
display: inline-block;
}
.before\:hx-w-px::before {
content: var(--tw-content);
width: 1px;
}
.before\:hx-bg-gray-200::before {
content: var(--tw-content);
--tw-bg-opacity: 1;
background-color: rgb(229 231 235 / var(--tw-bg-opacity));
}
.before\:hx-opacity-25::before {
content: var(--tw-content);
opacity: 0.25;
}
.before\:hx-transition-transform::before {
content: var(--tw-content);
transition-property: transform;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-duration: 150ms;
}
.before\:hx-content-\[\'\#\'\]::before {
--tw-content: '#';
content: var(--tw-content);
}
.before\:hx-content-\[\'\'\]::before {
--tw-content: '';
content: var(--tw-content);
}
.before\:hx-content-\[\\\"\\\"\]::before {
--tw-content: \"\";
content: var(--tw-content);
}
.first\:hx-mt-0:first-child {
margin-top: 0px;
}
@ -2872,15 +2998,6 @@ body:is(html[class~="dark"] *) {
border-color: rgb(163 163 163 / var(--tw-border-opacity));
}
.contrast-more\:hx-border-primary-500 {
--tw-border-opacity: 1;
border-color: hsl(var(--primary-hue) var(--primary-saturation) calc(calc(var(--primary-lightness) / 50) * 50) / var(--tw-border-opacity));
}
.contrast-more\:hx-border-transparent {
border-color: transparent;
}
.contrast-more\:hx-font-bold {
font-weight: 700;
}
@ -2919,11 +3036,6 @@ body:is(html[class~="dark"] *) {
--tw-shadow-colored: 0 0 #0000;
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
}
.contrast-more\:hover\:hx-border-gray-900:hover {
--tw-border-opacity: 1;
border-color: rgb(17 24 39 / var(--tw-border-opacity));
}
}
.dark\:hx-block:is(html[class~="dark"] *) {
display: block;
@ -2931,6 +3043,9 @@ body:is(html[class~="dark"] *) {
.dark\:hx-hidden:is(html[class~="dark"] *) {
display: none;
}
.dark\:hx-border-amber-200\/30:is(html[class~="dark"] *) {
border-color: rgb(253 230 138 / 0.3);
}
.dark\:hx-border-blue-200\/30:is(html[class~="dark"] *) {
border-color: rgb(191 219 254 / 0.3);
}
@ -2941,6 +3056,12 @@ body:is(html[class~="dark"] *) {
--tw-border-opacity: 1;
border-color: rgb(156 163 175 / var(--tw-border-opacity));
}
.dark\:hx-border-green-200\/30:is(html[class~="dark"] *) {
border-color: rgb(187 247 208 / 0.3);
}
.dark\:hx-border-indigo-200\/30:is(html[class~="dark"] *) {
border-color: rgb(199 210 254 / 0.3);
}
.dark\:hx-border-neutral-700:is(html[class~="dark"] *) {
--tw-border-opacity: 1;
border-color: rgb(64 64 64 / var(--tw-border-opacity));
@ -2961,6 +3082,9 @@ body:is(html[class~="dark"] *) {
.dark\:hx-border-yellow-200\/30:is(html[class~="dark"] *) {
border-color: rgb(254 240 138 / 0.3);
}
.dark\:hx-bg-amber-900\/30:is(html[class~="dark"] *) {
background-color: rgb(120 53 15 / 0.3);
}
.dark\:hx-bg-black\/60:is(html[class~="dark"] *) {
background-color: rgb(0 0 0 / 0.6);
}
@ -2977,6 +3101,12 @@ body:is(html[class~="dark"] *) {
.dark\:hx-bg-gray-50\/10:is(html[class~="dark"] *) {
background-color: rgb(249 250 251 / 0.1);
}
.dark\:hx-bg-green-900\/30:is(html[class~="dark"] *) {
background-color: rgb(20 83 45 / 0.3);
}
.dark\:hx-bg-indigo-900\/30:is(html[class~="dark"] *) {
background-color: rgb(49 46 129 / 0.3);
}
.dark\:hx-bg-neutral-800:is(html[class~="dark"] *) {
--tw-bg-opacity: 1;
background-color: rgb(38 38 38 / var(--tw-bg-opacity));
@ -2991,9 +3121,6 @@ body:is(html[class~="dark"] *) {
.dark\:hx-bg-primary-300\/10:is(html[class~="dark"] *) {
background-color: hsl(var(--primary-hue) var(--primary-saturation) calc(var(--primary-lightness) + calc(calc(100% - var(--primary-lightness)) / 50) * 27) / 0.1);
}
.dark\:hx-bg-primary-400\/10:is(html[class~="dark"] *) {
background-color: hsl(var(--primary-hue) var(--primary-saturation) calc(var(--primary-lightness) + calc(calc(100% - var(--primary-lightness)) / 50) * 16) / 0.1);
}
.dark\:hx-bg-primary-600:is(html[class~="dark"] *) {
--tw-bg-opacity: 1;
background-color: hsl(var(--primary-hue) var(--primary-saturation) calc(calc(var(--primary-lightness) / 50) * 45) / var(--tw-bg-opacity));
@ -3012,6 +3139,10 @@ body:is(html[class~="dark"] *) {
.dark\:hx-to-gray-400:is(html[class~="dark"] *) {
--tw-gradient-to: #9ca3af var(--tw-gradient-to-position);
}
.dark\:hx-text-amber-200:is(html[class~="dark"] *) {
--tw-text-opacity: 1;
color: rgb(253 230 138 / var(--tw-text-opacity));
}
.dark\:hx-text-blue-200:is(html[class~="dark"] *) {
--tw-text-opacity: 1;
color: rgb(191 219 254 / var(--tw-text-opacity));
@ -3036,22 +3167,22 @@ body:is(html[class~="dark"] *) {
--tw-text-opacity: 1;
color: rgb(249 250 251 / var(--tw-text-opacity));
}
.dark\:hx-text-green-200:is(html[class~="dark"] *) {
--tw-text-opacity: 1;
color: rgb(187 247 208 / var(--tw-text-opacity));
}
.dark\:hx-text-indigo-200:is(html[class~="dark"] *) {
--tw-text-opacity: 1;
color: rgb(199 210 254 / var(--tw-text-opacity));
}
.dark\:hx-text-neutral-200:is(html[class~="dark"] *) {
--tw-text-opacity: 1;
color: rgb(229 229 229 / var(--tw-text-opacity));
}
.dark\:hx-text-neutral-400:is(html[class~="dark"] *) {
--tw-text-opacity: 1;
color: rgb(163 163 163 / var(--tw-text-opacity));
}
.dark\:hx-text-orange-300:is(html[class~="dark"] *) {
--tw-text-opacity: 1;
color: rgb(253 186 116 / var(--tw-text-opacity));
}
.dark\:hx-text-primary-600:is(html[class~="dark"] *) {
--tw-text-opacity: 1;
color: hsl(var(--primary-hue) var(--primary-saturation) calc(calc(var(--primary-lightness) / 50) * 45) / var(--tw-text-opacity));
}
.dark\:hx-text-red-200:is(html[class~="dark"] *) {
--tw-text-opacity: 1;
color: rgb(254 202 202 / var(--tw-text-opacity));
@ -3093,11 +3224,6 @@ body:is(html[class~="dark"] *) {
--tw-text-opacity: 1;
color: rgb(156 163 175 / var(--tw-text-opacity));
}
.dark\:before\:hx-bg-neutral-800:is(html[class~="dark"] *)::before {
content: var(--tw-content);
--tw-bg-opacity: 1;
background-color: rgb(38 38 38 / var(--tw-bg-opacity));
}
.dark\:before\:hx-invert:is(html[class~="dark"] *)::before {
content: var(--tw-content);
--tw-invert: invert(100%);
@ -3189,6 +3315,14 @@ body:is(html[class~="dark"] *) {
--tw-ring-opacity: 1;
--tw-ring-color: hsl(var(--primary-hue) var(--primary-saturation) calc(calc(var(--primary-lightness) / 50) * 32) / var(--tw-ring-opacity));
}
.data-\[state\=selected\]\:dark\:hx-border-primary-500:is(html[class~="dark"] *)[data-state="selected"] {
--tw-border-opacity: 1;
border-color: hsl(var(--primary-hue) var(--primary-saturation) calc(calc(var(--primary-lightness) / 50) * 50) / var(--tw-border-opacity));
}
.data-\[state\=selected\]\:dark\:hx-text-primary-600:is(html[class~="dark"] *)[data-state="selected"] {
--tw-text-opacity: 1;
color: hsl(var(--primary-hue) var(--primary-saturation) calc(calc(var(--primary-lightness) / 50) * 45) / var(--tw-text-opacity));
}
@media (prefers-contrast: more) {
.contrast-more\:dark\:hx-border-current:is(html[class~="dark"] *) {
@ -3205,11 +3339,6 @@ body:is(html[class~="dark"] *) {
border-color: rgb(163 163 163 / var(--tw-border-opacity));
}
.contrast-more\:dark\:hx-border-primary-500:is(html[class~="dark"] *) {
--tw-border-opacity: 1;
border-color: hsl(var(--primary-hue) var(--primary-saturation) calc(calc(var(--primary-lightness) / 50) * 50) / var(--tw-border-opacity));
}
.dark\:contrast-more\:hx-border-neutral-400:is(html[class~="dark"] *) {
--tw-border-opacity: 1;
border-color: rgb(163 163 163 / var(--tw-border-opacity));
@ -3245,11 +3374,6 @@ body:is(html[class~="dark"] *) {
--tw-shadow-colored: 0 0 #0000;
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
}
.contrast-more\:dark\:hover\:hx-border-gray-50:hover:is(html[class~="dark"] *) {
--tw-border-opacity: 1;
border-color: rgb(249 250 251 / var(--tw-border-opacity));
}
}
@media not all and (min-width: 1280px) {
@ -3397,9 +3521,6 @@ body:is(html[class~="dark"] *) {
.ltr\:hx-ml-1:where([dir="ltr"], [dir="ltr"] *) {
margin-left: 0.25rem;
}
.ltr\:hx-ml-3:where([dir="ltr"], [dir="ltr"] *) {
margin-left: 0.75rem;
}
.ltr\:hx-ml-auto:where([dir="ltr"], [dir="ltr"] *) {
margin-left: auto;
}
@ -3449,10 +3570,6 @@ body:is(html[class~="dark"] *) {
.ltr\:hx-text-right:where([dir="ltr"], [dir="ltr"] *) {
text-align: right;
}
.ltr\:before\:hx-left-0:where([dir="ltr"], [dir="ltr"] *)::before {
content: var(--tw-content);
left: 0px;
}
@media (min-width: 768px) {
.ltr\:md\:hx-left-auto:where([dir="ltr"], [dir="ltr"] *) {
@ -3474,9 +3591,6 @@ body:is(html[class~="dark"] *) {
.rtl\:hx-mr-1:where([dir="rtl"], [dir="rtl"] *) {
margin-right: 0.25rem;
}
.rtl\:hx-mr-3:where([dir="rtl"], [dir="rtl"] *) {
margin-right: 0.75rem;
}
.rtl\:hx-mr-auto:where([dir="rtl"], [dir="rtl"] *) {
margin-right: auto;
}
@ -3520,10 +3634,6 @@ body:is(html[class~="dark"] *) {
.rtl\:hx-text-left:where([dir="rtl"], [dir="rtl"] *) {
text-align: left;
}
.rtl\:before\:hx-right-0:where([dir="rtl"], [dir="rtl"] *)::before {
content: var(--tw-content);
right: 0px;
}
.rtl\:before\:hx-rotate-180:where([dir="rtl"], [dir="rtl"] *)::before {
content: var(--tw-content);
--tw-rotate: 180deg;

View File

@ -1,5 +1,5 @@
@media (max-width: 767px) {
.sidebar-container {
.hextra-sidebar-container {
@apply hx-fixed hx-pt-[calc(var(--navbar-height))] hx-top-0 hx-w-full hx-bottom-0 hx-z-[15] hx-overscroll-contain hx-bg-white dark:hx-bg-dark;
transition: transform 0.8s cubic-bezier(0.52, 0.16, 0.04, 1);
will-change: transform, opacity;
@ -8,7 +8,7 @@
}
}
.sidebar-container {
.hextra-sidebar-container {
li > div {
@apply hx-h-0;
}
@ -18,4 +18,19 @@
li.open > a > span > svg > path {
@apply hx-rotate-90;
}
.hextra-sidebar-item-list {
@apply hx-relative hx-flex hx-flex-col hx-gap-1 before:hx-absolute before:hx-inset-y-1 before:hx-w-px before:hx-bg-gray-200 ltr:hx-ml-3 ltr:hx-pl-3 ltr:before:hx-left-0 rtl:hx-mr-3 rtl:hx-pr-3 rtl:before:hx-right-0 dark:before:hx-bg-neutral-800;
}
.hextra-sidebar-item-link {
@apply hx-flex hx-items-center hx-justify-between hx-gap-2 hx-cursor-pointer hx-rounded hx-px-2 hx-py-1.5 hx-text-sm hx-transition-colors;
&.active {
@apply hx-bg-primary-100 hx-font-semibold hx-text-primary-800 contrast-more:hx-border contrast-more:hx-border-primary-500 dark:hx-bg-primary-400/10 dark:hx-text-primary-600 contrast-more:dark:hx-border-primary-500;
}
&.inactive {
@apply hx-text-gray-500 hover:hx-bg-gray-100 hover:hx-text-gray-900 contrast-more:hx-border contrast-more:hx-border-transparent contrast-more:hx-text-gray-900 contrast-more:hover:hx-border-gray-900 dark:hx-text-neutral-400 dark:hover:hx-bg-primary-100/5 dark:hover:hx-text-gray-50 contrast-more:dark:hx-text-gray-50 contrast-more:dark:hover:hx-border-gray-50;
}
}
}

View File

@ -3,7 +3,7 @@
document.addEventListener('DOMContentLoaded', function () {
const menu = document.querySelector('.hamburger-menu');
const overlay = document.querySelector('.mobile-menu-overlay');
const sidebarContainer = document.querySelector('.sidebar-container');
const sidebarContainer = document.querySelector('.hextra-sidebar-container');
// Initialize the overlay
const overlayClasses = ['hx-fixed', 'hx-inset-0', 'hx-z-10', 'hx-bg-black/80', 'dark:hx-bg-black/60'];

View File

@ -1,3 +1,12 @@
/**
* Check if the element is visible.
* @param {Element} element Dom element
* @returns boolean
*/
function isVisible(element) {
return element.offsetWidth > 0 || element.offsetHeight > 0;
}
document.addEventListener("DOMContentLoaded", function () {
scrollToActiveItem();
enableCollapsibles();
@ -10,10 +19,43 @@ function enableCollapsibles() {
e.preventDefault();
const list = button.parentElement.parentElement;
if (list) {
list.classList.toggle("open")
list.classList.toggle("open");
}
});
});
const isCached = "{{- site.Params.page.sidebar.cache | default false -}}" === "true";
const currentPagePath = window.location.href;
if (isCached) {
// find the current page in the sidebar and open the parent lists
const sidebar = document.querySelector(".hextra-sidebar-container");
if (sidebar) {
// find a tags and compare href with current page path
const links = sidebar.querySelectorAll("a");
links.forEach(function (link) {
const linkPath = link.href;
if (currentPagePath === linkPath) {
// add active class to the link
link.classList.add("active");
link.classList.remove("inactive");
if (!isVisible(link)) {
return;
}
// recursively open parent lists
let parent = link.parentElement;
while (parent && !parent.classList.contains("hextra-sidebar-container")) {
if (parent.tagName === "LI" && parent.classList.contains("hextra-sidebar-item")) {
parent.classList.add("open");
}
parent = parent.parentElement;
}
}
});
}
}
}
function scrollToActiveItem() {
@ -31,6 +73,6 @@ function scrollToActiveItem() {
const yDistance = visibleActiveItem.getBoundingClientRect().top - sidebarScrollbar.getBoundingClientRect().top;
sidebarScrollbar.scrollTo({
behavior: "instant",
top: yDistance - yOffset
top: yDistance - yOffset,
});
}

View File

@ -289,3 +289,4 @@ youtube: <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill=
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>
slack: <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="currentColor" d="M5.042 15.165a2.528 2.528 0 0 1-2.52 2.523A2.528 2.528 0 0 1 0 15.165a2.527 2.527 0 0 1 2.522-2.52h2.52zm1.271 0a2.527 2.527 0 0 1 2.521-2.52a2.527 2.527 0 0 1 2.521 2.52v6.313A2.528 2.528 0 0 1 8.834 24a2.528 2.528 0 0 1-2.521-2.522zM8.834 5.042a2.528 2.528 0 0 1-2.521-2.52A2.528 2.528 0 0 1 8.834 0a2.528 2.528 0 0 1 2.521 2.522v2.52zm0 1.271a2.528 2.528 0 0 1 2.521 2.521a2.528 2.528 0 0 1-2.521 2.521H2.522A2.528 2.528 0 0 1 0 8.834a2.528 2.528 0 0 1 2.522-2.521zm10.122 2.521a2.528 2.528 0 0 1 2.522-2.521A2.528 2.528 0 0 1 24 8.834a2.528 2.528 0 0 1-2.522 2.521h-2.522zm-1.268 0a2.528 2.528 0 0 1-2.523 2.521a2.527 2.527 0 0 1-2.52-2.521V2.522A2.527 2.527 0 0 1 15.165 0a2.528 2.528 0 0 1 2.523 2.522zm-2.523 10.122a2.528 2.528 0 0 1 2.523 2.522A2.528 2.528 0 0 1 15.165 24a2.527 2.527 0 0 1-2.52-2.522v-2.522zm0-1.268a2.527 2.527 0 0 1-2.52-2.523a2.526 2.526 0 0 1 2.52-2.52h6.313A2.527 2.527 0 0 1 24 15.165a2.528 2.528 0 0 1-2.522 2.523z" /></svg>
bluesky: <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 530"><path fill="currentColor" d="M136 44c66 50 138 151 164 205 26-54 98-155 164-205 48-36 126-64 126 25 0 18-10 149-16 170-21 74-96 93-163 81 117 20 147 86 82 153-122 125-176-32-189-72-3-8-4-11-4-8 0-3-1 0-4 8-13 40-67 197-189 72-65-67-35-133 82-153-67 12-142-7-163-81-6-21-16-152-16-170 0-89 78-61 126-25z"/></svg>

View File

@ -44,6 +44,128 @@ The primary color of the theme can be customized by setting the `--primary-hue`,
}
```
### Further Theme Customization
The theme can be further customized by overriding the default styles via the exposed css classes. An example for customizing the footer element:
```css {filename="assets/css/custom.css"}
.hextra-footer {
/* Styles will be applied to the footer element */
}
.hextra-footer:is(html[class~="dark"] *) {
/* Styles will be applied to the footer element in dark mode */
}
```
The following classes can be used to customize various parts of the theme.
#### General
- `hextra-scrollbar` - The scrollbar element
- `content` - Page content container
#### Shortcodes
##### Badge
- `hextra-badge` - The badge element
##### Card
- `hextra-card` - The card element
- `hextra-card-image` - The card image element
- `hextra-card-icon` - The card icon element
- `hextra-card-subtitle` - The card subtitle element
##### Cards
- `hextra-cards` - The cards grid container
##### Jupyter Notebook
- `hextra-jupyter-code-cell` - The Jupyter code cell container
- `hextra-jupyter-code-cell-outputs-container` - The Jupyter code cell outputs container
- `hextra-jupyter-code-cell-outputs` - The Jupyter code cell output div element
##### PDF
- `hextra-pdf` - The PDF container element
##### Steps
- `steps` - The steps container
##### Tabs
- `hextra-tabs-panel` - The tabs panel container
- `hextra-tabs-toggle` - The tabs toggle button
##### Filetree
- `hextra-filetree` - The filetree container
##### Folder
- `hextra-filetree-folder` - The filetree folder container
#### Navbar
- `nav-container` - The navbar container
- `nav-container-blur` - The navbar container in blur element
- `hamburger-menu` - The hamburger menu button
#### Footer
- `hextra-footer` - The footer element
- `hextra-custom-footer` - The custom footer section container
#### Search
- `search-wrapper` - The search wrapper container
- `search-input` - The search input element
- `search-results` - The search results list container
#### Table of Contents
- `hextra-toc` - The table of contents container
#### Sidebar
- `mobile-menu-overlay` - The overlay element for the mobile menu
- `sidebar-container` - The sidebar container
- `sidebar-active-item` - The active item in the sidebar
#### Language Switcher
- `language-switcher` - The language switcher button
- `language-options` - The language options container
#### Theme Toggle
- `theme-toggle` - The theme toggle button
#### Cody Copy Button
- `hextra-code-copy-btn-container` - The code copy button container
- `hextra-code-copy-btn` - The code copy button
#### Code Block
- `hextra-code-block` - The code block container
#### Feature Card
- `hextra-feature-card` - The feature card link element
#### Feature Grid
- `hextra-feature-grid` - The feature grid container
#### Breadcrumbs
No specific class is available for breadcrumbs.
### Syntax Highlighting
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:
@ -62,13 +184,28 @@ You may add custom scripts to the end of the head for every page by adding the f
layouts/partials/custom/head-end.html
```
## Custom Extra Section in Footer
You can add extra section in the footer by creating a file `layouts/partials/custom/footer.html` in your site.
```html {filename="layouts/partials/custom/footer.html"}
<!-- Your footer element here -->
```
The added section will be added before the copyright section in the footer.
You can use [HTML](https://developer.mozilla.org/en-US/docs/Web/HTML) and [Hugo template syntax](https://gohugo.io/templates/) to add your own content.
Hugo variables available in the footer section are: `.switchesVisible` and `.copyrightVisible`.
## Custom Layouts
The layouts of the theme can be overridden by creating a file with the same name in the `layouts` directory of your site.
For example, to override the `single.html` layout for docs, create a file `layouts/docs/single.html` in your site.
For further information, refer to the [Hugo Templates](https://gohugo.io/templates/).
For further information, refer to the [Hugo Templates][hugo-template-docs].
## 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!
[hugo-template-docs]: https://gohugo.io/templates/

View File

@ -87,7 +87,7 @@ params:
### Main Sidebar
For the main sidebar, it is automatically generated from the structure of the content directory.
By default, the main sidebar 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:
@ -119,6 +119,33 @@ menu:
weight: 3
```
### Sidebar from Data
Alternatively, you can define the sidebar structure in the `data` directory. This gives you more flexibility to define sidebar differently than your content structure. To enable this, set the `params.sidebar.source` parameter in the config file to `data`:
```yaml {filename="hugo.yaml"}
params:
sidebar:
source: data
```
To define the sidebar data, create a file named `sidebar.yaml` in the `data` directory.
```yaml {filename="data/sidebar.yaml"}
docs:
- title: Documentation
link: /docs/
- title: Guide
link: /docs/guide/
open: false
items:
- title: Configuration
link: /docs/guide/configuration/
# ...
```
If your site is multilingual, you can define the sidebar data for each language, for example in `data/en/sidebar.yaml` file.
## Right Sidebar
### Table of Contents

View File

@ -54,7 +54,7 @@ jobs:
build:
runs-on: ubuntu-latest
env:
HUGO_VERSION: 0.131.0
HUGO_VERSION: 0.138.0
steps:
- name: Checkout
uses: actions/checkout@v4
@ -146,7 +146,7 @@ For more details, check out:
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.132.2`
- Add Environment variable `HUGO_VERSION` and set to `0.138.0`, or alternatively, set it in `netlify.toml` file
4. Deploy!
Check [Hugo on Netlify](https://docs.netlify.com/integrations/frameworks/hugo/) for more details.

View File

@ -35,6 +35,46 @@ Blockquote with attribution
[^1]: The above quote is excerpted from Rob Pike's [talk](https://www.youtube.com/watch?v=PAAkCSZUG1c) during Gopherfest, November 18, 2015.
```
### Alerts
{{< new-feature version="v0.9.0" >}}
Alerts are a Markdown extension based on the blockquote syntax that you can use to emphasize critical information.
[GitHub-style alerts](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax#alerts) are supported.
Please make sure you are using the latest version of Hextra and [Hugo v0.134.0](https://github.com/gohugoio/hugo/releases/tag/v0.134.0) or later.
> [!NOTE]
> Useful information that users should know, even when skimming content.
> [!TIP]
> Helpful advice for doing things better or more easily.
> [!IMPORTANT]
> Key information users need to know to achieve their goal.
> [!WARNING]
> Urgent info that needs immediate user attention to avoid problems.
> [!CAUTION]
> Advises about risks or negative outcomes of certain actions.
```markdown {filename=Markdown}
> [!NOTE]
> Useful information that users should know, even when skimming content.
> [!TIP]
> Helpful advice for doing things better or more easily.
> [!IMPORTANT]
> Key information users need to know to achieve their goal.
> [!WARNING]
> Urgent info that needs immediate user attention to avoid problems.
> [!CAUTION]
> Advises about risks or negative outcomes of certain actions.
```
### Tables
Tables aren't part of the core Markdown spec, but Hugo supports them out-of-the-box.

View File

@ -10,6 +10,10 @@ A built-in component to show important information to the reader.
<!--more-->
> [!NOTE]
> [GitHub-style alerts](../../markdown#alerts) are supported since [v0.9.0](https://github.com/imfing/hextra/releases/tag/v0.9.0).
> It leverages Markdown syntax to render the callout which ensures better portability and readability of the content.
## Example
{{< callout emoji="👾">}}

View File

@ -34,16 +34,15 @@ Result:
{{< badge content="warning" type="warning" >}} &nbsp;
{{< badge content="error" type="error" >}}
With link:
With link and icon:
```
{{</* badge content="Releases" link="https://github.com/imfing/hextra/releases" */>}}
{{</* badge content="Releases" link="https://github.com/imfing/hextra/releases" icon="github" */>}}
```
Result:
{{< badge content="Releases" link="https://github.com/imfing/hextra/releases" >}}
{{< badge content="Releases" link="https://github.com/imfing/hextra/releases" icon="github" >}}
## YouTube

View File

@ -40,6 +40,24 @@ def say_hello():
print("Hello!")
```
### Link to File
{{< new-feature version="v0.9.2" >}}
You can use the `base_url` attribute to provide a base URL that will be combined with the file name to generate a link.
The file name can include a relative path if it specifies the file's location within the base path.
````markdown {filename="Markdown"}
```go {base_url="https://github.com/imfing/hextra/blob/main/",filename="exampleSite/hugo.work"}
go 1.20
```
````
```go {base_url="https://github.com/imfing/hextra/blob/main/",filename="exampleSite/hugo.work"}
go 1.20
```
### Line Numbers
To set line numbers, set attribute `linenos` to `table` and optionally set `linenostart` to the starting line number:

View File

@ -12,6 +12,26 @@ Open source projects powered by Hextra
</p>
{{< cards >}}
{{< card
link="https://github.com/modelcontextprotocol/specification"
title="Model Context Protocol Specification"
image="https://github.com/user-attachments/assets/1bb4f952-b8fc-43b5-9cbd-cd7213c2ba90"
imageStyle="object-fit:cover; aspect-ratio:16/9;"
>}}
{{< card
link="https://github.com/jonaspleyer/cellular_raza"
title="cellular_raza"
image="https://github.com/user-attachments/assets/f24c6455-b70a-419b-b025-e3d60101b673"
imageStyle="object-fit:cover; aspect-ratio:16/9;"
>}}
{{< card
link="https://github.com/mightymoud/sidekick"
title="Sidekick"
image="https://github.com/user-attachments/assets/4ae2a9d7-77b6-42eb-a9d7-5c4599f0f812"
imageStyle="object-fit:cover; aspect-ratio:16/9;"
>}}
{{< card
link="https://github.com/welding-torch/installc"
@ -75,7 +95,7 @@ Open source projects powered by Hextra
>}}
{{< card
link="https://lutheranconfessions.org/"
link="https://github.com/remysheppard/lutheran-confessions"
title="LutheranConfessions"
image="https://github.com/imfing/hextra/assets/5097752/ad6625e4-88cd-4cad-b102-5399997d0359"
imageStyle="object-fit:cover; aspect-ratio:16/9;"

View File

@ -0,0 +1,49 @@
docs:
- title: Documentation
link: /docs/
- title: Getting Started
link: /docs/getting-started/
- title: Guide
link: /docs/guide/
open: false
items:
- title: Organize Files
link: /docs/guide/organize-files/
- title: Configuration
link: /docs/guide/configuration/
- title: Markdown
link: /docs/guide/markdown/
- title: Syntax Highlighting
link: /docs/guide/syntax-highlighting/
- title: LaTeX
link: /docs/guide/latex/
- title: Diagrams
link: /docs/guide/diagrams/
- title: Shortcodes
link: /docs/guide/shortcodes/
items:
- title: Callout
link: /docs/guide/shortcodes/callout/
- title: Cards
link: /docs/guide/shortcodes/cards/
- title: Details
link: /docs/guide/shortcodes/details/
- title: FileTree
link: /docs/guide/shortcodes/filetree/
- title: Icon
link: /docs/guide/shortcodes/icon/
- title: Steps
link: /docs/guide/shortcodes/steps/
- title: Tabs
link: /docs/guide/shortcodes/tabs/
- title: Deploy Site
link: /docs/guide/deploy-site/
- title: Advanced
link: /docs/advanced/
items:
- title: Multi-language
link: /docs/advanced/multi-language/
- title: Comments
link: /docs/advanced/comments/
- title: Customization
link: /docs/advanced/customization/

View File

@ -113,6 +113,10 @@ params:
# full (100%), wide (90rem), normal (1280px)
width: normal
# TODO: move one level up
sidebar:
source: data
theme:
# light | dark | system
default: system
@ -173,3 +177,4 @@ params:
# emitMetadata: 0
# inputPosition: top
# lang: en
# theme: noborder_dark

View File

@ -69,46 +69,36 @@
"[hyphens:auto]",
"[transition:background-color_1.5s_ease]",
"[word-break:break-word]",
"active",
"active:hx-bg-gray-400/20",
"active:hx-opacity-50",
"active:hx-shadow-gray-200",
"active:hx-shadow-sm",
"before:hx-absolute",
"before:hx-bg-glass-gradient",
"before:hx-bg-gray-200",
"before:hx-content-[\"\"]",
"before:hx-content-['#']",
"before:hx-content-['']",
"before:hx-inline-block",
"before:hx-inset-0",
"before:hx-inset-y-1",
"before:hx-mr-1",
"before:hx-opacity-25",
"before:hx-pointer-events-none",
"before:hx-transition-transform",
"before:hx-w-px",
"chroma",
"content",
"contrast-more:dark:hover:hx-border-gray-50",
"contrast-more:dark:hx-border-current",
"contrast-more:dark:hx-border-gray-50",
"contrast-more:dark:hx-border-neutral-400",
"contrast-more:dark:hx-border-primary-500",
"contrast-more:dark:hx-shadow-[0_0_0_1px_#fff]",
"contrast-more:dark:hx-shadow-none",
"contrast-more:dark:hx-text-current",
"contrast-more:dark:hx-text-gray-100",
"contrast-more:dark:hx-text-gray-300",
"contrast-more:dark:hx-text-gray-50",
"contrast-more:hover:hx-border-gray-900",
"contrast-more:hx-border",
"contrast-more:hx-border-current",
"contrast-more:hx-border-gray-800",
"contrast-more:hx-border-gray-900",
"contrast-more:hx-border-neutral-400",
"contrast-more:hx-border-primary-500",
"contrast-more:hx-border-t",
"contrast-more:hx-border-transparent",
"contrast-more:hx-font-bold",
"contrast-more:hx-shadow-[0_0_0_1px_#000]",
"contrast-more:hx-shadow-none",
@ -118,7 +108,6 @@
"contrast-more:hx-text-gray-900",
"contrast-more:hx-underline",
"copy-icon",
"dark:before:hx-bg-neutral-800",
"dark:before:hx-invert",
"dark:contrast-more:hx-border-neutral-400",
"dark:focus:hx-bg-dark",
@ -141,23 +130,28 @@
"dark:hover:hx-text-gray-50",
"dark:hover:hx-text-neutral-50",
"dark:hover:hx-text-white",
"dark:hx-bg-amber-900/30",
"dark:hx-bg-black/60",
"dark:hx-bg-blue-900/30",
"dark:hx-bg-dark",
"dark:hx-bg-dark/50",
"dark:hx-bg-gray-50/10",
"dark:hx-bg-green-900/30",
"dark:hx-bg-indigo-900/30",
"dark:hx-bg-neutral-800",
"dark:hx-bg-neutral-900",
"dark:hx-bg-orange-400/20",
"dark:hx-bg-primary-300/10",
"dark:hx-bg-primary-400/10",
"dark:hx-bg-primary-600",
"dark:hx-bg-red-900/30",
"dark:hx-bg-yellow-700/30",
"dark:hx-block",
"dark:hx-border-amber-200/30",
"dark:hx-border-blue-200/30",
"dark:hx-border-gray-100/20",
"dark:hx-border-gray-400",
"dark:hx-border-green-200/30",
"dark:hx-border-indigo-200/30",
"dark:hx-border-neutral-700",
"dark:hx-border-neutral-800",
"dark:hx-border-orange-400/30",
@ -171,16 +165,17 @@
"dark:hx-shadow-[0_-12px_16px_#111]",
"dark:hx-shadow-[0_-1px_0_rgba(255,255,255,.1)_inset]",
"dark:hx-shadow-none",
"dark:hx-text-amber-200",
"dark:hx-text-blue-200",
"dark:hx-text-gray-100",
"dark:hx-text-gray-200",
"dark:hx-text-gray-300",
"dark:hx-text-gray-400",
"dark:hx-text-gray-50",
"dark:hx-text-green-200",
"dark:hx-text-indigo-200",
"dark:hx-text-neutral-200",
"dark:hx-text-neutral-400",
"dark:hx-text-orange-300",
"dark:hx-text-primary-600",
"dark:hx-text-red-200",
"dark:hx-text-slate-100",
"dark:hx-text-yellow-200",
@ -188,6 +183,8 @@
"dark:placeholder:hx-text-gray-400",
"data-[state=closed]:hx-hidden",
"data-[state=open]:hx-hidden",
"data-[state=selected]:dark:hx-border-primary-500",
"data-[state=selected]:dark:hx-text-primary-600",
"data-[state=selected]:hx-block",
"data-[state=selected]:hx-border-primary-500",
"data-[state=selected]:hx-text-primary-600",
@ -219,6 +216,7 @@
"hextra-code-block",
"hextra-code-copy-btn",
"hextra-code-copy-btn-container",
"hextra-custom-footer",
"hextra-feature-card",
"hextra-feature-grid",
"hextra-filetree",
@ -230,6 +228,10 @@
"hextra-pdf",
"hextra-scrollbar",
"hextra-sidebar-collapsible-button",
"hextra-sidebar-container",
"hextra-sidebar-item",
"hextra-sidebar-item-link",
"hextra-sidebar-item-list",
"hextra-tabs-panel",
"hextra-tabs-toggle",
"hextra-toc",
@ -256,18 +258,21 @@
"hover:hx-text-primary-600",
"hx-absolute",
"hx-align-[-2.5px]",
"hx-align-middle",
"hx-align-text-bottom",
"hx-appearance-none",
"hx-aspect-auto",
"hx-bg-amber-100",
"hx-bg-black/80",
"hx-bg-black/[.05]",
"hx-bg-blue-100",
"hx-bg-clip-text",
"hx-bg-gradient-to-r",
"hx-bg-gray-100",
"hx-bg-green-100",
"hx-bg-indigo-100",
"hx-bg-neutral-50",
"hx-bg-orange-50",
"hx-bg-primary-100",
"hx-bg-primary-400",
"hx-bg-primary-600",
"hx-bg-primary-700/5",
@ -277,12 +282,15 @@
"hx-bg-yellow-50",
"hx-block",
"hx-border",
"hx-border-amber-200",
"hx-border-b",
"hx-border-b-2",
"hx-border-black/5",
"hx-border-blue-200",
"hx-border-gray-200",
"hx-border-gray-500",
"hx-border-green-200",
"hx-border-indigo-200",
"hx-border-orange-100",
"hx-border-red-200",
"hx-border-t",
@ -336,7 +344,6 @@
"hx-inset-y-0",
"hx-items-center",
"hx-items-start",
"hx-justify-between",
"hx-justify-center",
"hx-justify-end",
"hx-justify-items-start",
@ -468,6 +475,7 @@
"hx-text-[.65rem]",
"hx-text-[10px]",
"hx-text-[color:hsl(var(--primary-hue),100%,50%)]",
"hx-text-amber-900",
"hx-text-base",
"hx-text-blue-900",
"hx-text-center",
@ -479,10 +487,11 @@
"hx-text-gray-700",
"hx-text-gray-800",
"hx-text-gray-900",
"hx-text-green-900",
"hx-text-indigo-900",
"hx-text-left",
"hx-text-lg",
"hx-text-orange-800",
"hx-text-primary-800",
"hx-text-red-900",
"hx-text-slate-900",
"hx-text-sm",
@ -520,16 +529,15 @@
"hx-z-20",
"hx-z-[-1]",
"icon",
"inactive",
"language-options",
"language-switcher",
"last-of-type:hx-mb-0",
"lntable",
"lntd",
"ltr:before:hx-left-0",
"ltr:hx--mr-4",
"ltr:hx-border-l",
"ltr:hx-ml-1",
"ltr:hx-ml-3",
"ltr:hx-ml-auto",
"ltr:hx-mr-auto",
"ltr:hx-pl-12",
@ -581,7 +589,6 @@
"print:hx-bg-transparent",
"print:hx-hidden",
"rtl:-hx-rotate-180",
"rtl:before:hx-right-0",
"rtl:before:hx-rotate-180",
"rtl:hx--ml-4",
"rtl:hx-border-r",
@ -589,7 +596,6 @@
"rtl:hx-left-3",
"rtl:hx-ml-auto",
"rtl:hx-mr-1",
"rtl:hx-mr-3",
"rtl:hx-mr-auto",
"rtl:hx-pl-2",
"rtl:hx-pl-4",
@ -606,8 +612,6 @@
"search-input",
"search-results",
"search-wrapper",
"sidebar-active-item",
"sidebar-container",
"sm:hx-block",
"sm:hx-flex",
"sm:hx-items-start",

View File

@ -0,0 +1,11 @@
{{- $version := .Get "version" | default "" -}}
{{- $icon := .Get "icon" | default "" -}}
{{- $defaultLink := cond (eq $version "") "https://github.com/imfing/hextra/tree/main" (printf "https://github.com/imfing/hextra/releases/tag/%s" $version) -}}
{{- $link := .Get "link" | default $defaultLink -}}
{{- $content := cond (eq $version "") "New in main branch" (printf "New in %s" $version) -}}
<div style="margin-top: 1rem; display: inline-flex;">
<a href="{{ $link }}" title="{{ $link | plainify }}" target="_blank">
{{- partial "shortcodes/badge" (dict "content" $content "border" true "icon" $icon) -}}
</a>
</div>

View File

@ -0,0 +1,9 @@
{{- if not (in (slice "note" "tip" "important" "warning" "caution") .AlertType) -}}
{{- warnf "Alert type %s is not supported" .AlertType -}}
{{- end -}}
{{- $content := .Text -}}
{{- $alertType := .AlertType -}}
{{- $alertTitle := .AlertTitle -}}
{{- partial "components/github-style-alert.html" (dict "content" $content "alertType" $alertType "alertTitle" $alertTitle) -}}

View File

@ -0,0 +1,3 @@
<blockquote>
{{ .Text }}
</blockquote>

View File

@ -1,12 +1,13 @@
{{- $class := .Attributes.class | default "" -}}
{{- $filename := .Attributes.filename | default "" -}}
{{- $base_url := .Attributes.base_url | default "" -}}
{{- $lang := .Attributes.lang | default .Type -}}
<div class="hextra-code-block hx-relative hx-mt-6 first:hx-mt-0 hx-group/code">
{{ partial "components/codeblock" (dict "filename" $filename "lang" $lang "content" .Inner "options" .Options) }}
{{- partial "components/codeblock" (dict "filename" $filename "lang" $lang "base_url" $base_url "content" .Inner "options" .Options) -}}
{{- if or (eq site.Params.highlight.copy.enable nil) (site.Params.highlight.copy.enable) }}
{{- partialCached "components/codeblock-copy-button" (dict "filename" $filename) $filename }}
{{ end }}
{{- if or (eq site.Params.highlight.copy.enable nil) (site.Params.highlight.copy.enable) -}}
{{- partialCached "components/codeblock-copy-button" (dict "filename" $filename) $filename -}}
{{- end -}}
</div>

View File

@ -1,6 +1,8 @@
{{ define "main" }}
<div class='hx-mx-auto hx-flex {{ partial "utils/page-width" . }}'>
{{ partial "sidebar.html" (dict "context" .) }}
{{- if not (in (slice "taxonomy" "term") .Kind) -}}
{{- partial "sidebar.html" (dict "context" .) -}}
{{- end -}}
{{ partial "toc.html" . }}
<article class="hx-w-full hx-break-words hx-flex hx-min-h-[calc(100vh-var(--navbar-height))] hx-min-w-0 hx-justify-center hx-pb-8 hx-pr-[calc(env(safe-area-inset-right)-1.5rem)]">
<main class="hx-w-full hx-min-w-0 hx-max-w-6xl hx-px-6 hx-pt-4 md:hx-px-12">

View File

@ -1,11 +1,27 @@
{{ $filename := .filename | default "" -}}
{{ $base_url := .base_url | default "" -}}
{{ $lang := .lang | default "" }}
{{ $content := .content }}
{{ $options := .options | default (dict) }}
{{- if $filename -}}
<div class="filename" dir="auto">{{ $filename }}</div>
<div class="filename not-prose" dir="auto">
{{- if $base_url -}}
{{- $base_url = strings.TrimSuffix "/" $base_url -}}
{{- $filename = strings.TrimPrefix "/" $filename -}}
{{- $file_url := urls.JoinPath $base_url $filename -}}
<a class="hx-no-underline hx-inline-flex hx-items-center hx-gap-1" href="{{ $file_url }}" target="_blank" rel="noopener noreferrer">
<span>{{- $filename -}}</span>
{{- partial "utils/icon" (dict "name" "external-link" "attributes" "height=1em") -}}
</a>
{{- else -}}
{{- $filename -}}
{{- end -}}
</div>
{{- end -}}
{{- if transform.CanHighlight $lang -}}
<div>{{- highlight $content $lang $options -}}</div>
{{- else -}}

View File

@ -8,10 +8,19 @@
* This solution was created with reference to:
* https://github.com/giscus/giscus/issues/336#issuecomment-1214366281
*/
function getGiscusTheme() {
function getHugoTheme() {
return localStorage.getItem("color-theme");
}
function getGiscusTheme() {
let giscusTheme = "{{ (string .theme) | default `light` }}";
if(getHugoTheme() == 'light') {
return giscusTheme.replace('dark', 'light');
} else {
return giscusTheme.replace('light', 'dark');
}
}
function setGiscusTheme() {
function sendMessage(message) {
const iframe = document.querySelector('iframe.giscus-frame');

View File

@ -0,0 +1,42 @@
{{- $content := .content -}}
{{- $alertType := .alertType -}}
{{- $alertTitle := .alertTitle -}}
{{- $icons := dict
"note" "information-circle"
"tip" "light-bulb"
"important" "information-circle"
"warning" "exclamation"
"caution" "exclamation-circle"
-}}
{{- $icon := index $icons $alertType -}}
{{- $title := or $alertTitle (or (i18n $alertType) (title $alertType)) -}}
{{- $defaultClass := "hx-border-orange-100 hx-bg-orange-50 hx-text-orange-800 dark:hx-border-orange-400/30 dark:hx-bg-orange-400/20 dark:hx-text-orange-300" }}
{{- $alertClasses := dict
"note" "hx-border-blue-200 hx-bg-blue-100 hx-text-blue-900 dark:hx-border-blue-200/30 dark:hx-bg-blue-900/30 dark:hx-text-blue-200"
"tip" "hx-border-green-200 hx-bg-green-100 hx-text-green-900 dark:hx-border-green-200/30 dark:hx-bg-green-900/30 dark:hx-text-green-200"
"important" "hx-border-indigo-200 hx-bg-indigo-100 hx-text-indigo-900 dark:hx-border-indigo-200/30 dark:hx-bg-indigo-900/30 dark:hx-text-indigo-200"
"warning" "hx-border-amber-200 hx-bg-amber-100 hx-text-amber-900 dark:hx-border-amber-200/30 dark:hx-bg-amber-900/30 dark:hx-text-amber-200"
"caution" "hx-border-red-200 hx-bg-red-100 hx-text-red-900 dark:hx-border-red-200/30 dark:hx-bg-red-900/30 dark:hx-text-red-200"
-}}
{{- $class := index $alertClasses $alertType | default $defaultClass -}}
<div class="hx-overflow-x-auto hx-mt-6 hx-flex hx-flex-col hx-rounded-lg hx-border hx-py-4 hx-px-4 contrast-more:hx-border-current contrast-more:dark:hx-border-current {{ $class }}">
<p class="hx-flex hx-items-center hx-font-medium">
{{- with $icon -}}
{{- partial "utils/icon.html" (dict "name" . "attributes" `height=16px class="hx-inline-block hx-align-middle hx-mr-2"`) -}}
{{- end -}}
{{- $title -}}
</p>
<div class="hx-w-full hx-min-w-0 hx-leading-7">
<div class="hx-mt-6 hx-leading-7 first:hx-mt-0">
{{- $content -}}
</div>
</div>
</div>

View File

@ -0,0 +1,12 @@
{{- range site.Menus.sidebar }}
{{- $name := or (T .Identifier) .Name }}
{{- if eq .Params.type "separator" }}
<li class="[word-break:break-word] hx-mt-5 hx-mb-2 hx-px-2 hx-py-1.5 hx-text-sm hx-font-semibold hx-text-gray-900 first:hx-mt-0 dark:hx-text-gray-100">
<span class="hx-cursor-default">{{ $name }}</span>
</li>
{{- else }}
<li>
{{- partial "components/sidebar/item-link" (dict "active" false "title" $name "link" (.URL | relLangURL)) -}}
</li>
{{- end }}
{{- end -}}

View File

@ -0,0 +1,5 @@
<span class="hextra-sidebar-collapsible-button">
<svg fill="none" viewBox="0 0 24 24" stroke="currentColor" class="hx-h-[18px] hx-min-w-[18px] hx-rounded-sm hx-p-0.5 hover:hx-bg-gray-800/5 dark:hover:hx-bg-gray-100/5">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" class="hx-origin-center hx-transition-transform rtl:-hx-rotate-180"></path>
</svg>
</span>

View File

@ -0,0 +1,35 @@
{{/* Generate mobile navigation data based on main menu */}}
{{- $context := . -}}
{{- $data := slice -}}
{{- range .Site.Menus.main -}}
{{- if not (eq .Params.type "search") -}}
{{- $title := or (T .Identifier) .Name -}}
{{- $link := .URL -}}
{{- $external := strings.HasPrefix $link "http" -}}
{{- with .PageRef -}}
{{- if hasPrefix . "/" -}}
{{- $link = relLangURL (strings.TrimPrefix "/" .) -}}
{{- end -}}
{{- end -}}
{{- with .Page -}}
{{- $page := . -}}
{{- if and $page.IsSection (eq $page.Type "docs") -}}
{{- $page = (partial "utils/translated-page" (dict "page" $page "lang" site.Language.LanguageCode)) -}}
{{- $sectionData := (partial "components/sidebar/generate-section-data" $page) | unmarshal -}}
{{- $data = $data | append (dict "title" $title "link" $link "items" $sectionData) -}}
{{- else -}}
{{- $data = $data | append (dict "title" $title "link" $link) -}}
{{- end -}}
{{- else -}}
{{/* TODO: handle other cases like external links */}}
{{- $data = $data | append (dict "title" $title "link" $link) -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{- return ($data | jsonify (dict "noHTMLEscape" true)) -}}

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": "{{ partial "utils/title" . }}",
"link": "{{ .RelPermalink }}",
"toc": {{ partial "sidebar/section-page-toc" . }},
"open": {{ .Params.sidebar.open | default false }}
{{- if .IsSection }},
"items": [
{{ $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,20 @@
{{/* Get section sidebar config from Hugo `data` directory
If the site is multilingual, the sidebar data is stored in a language-specific
directory. For example, the English sidebar data is stored in `data/en/sidebar.yaml`.
*/}}
{{ $data := "" }}
{{ $section := .Section | default "index" }}
{{ $filename := "sidebar" }}
{{ if hugo.IsMultilingual }}
{{ with (index site.Data site.Language.Lang $filename $section) }}
{{ $data = . }}
{{ end }}
{{ else }}
{{ with (index site.Data $filename $section) }}
{{ $data = . }}
{{ end }}
{{ end }}
{{ return $data }}

View File

@ -0,0 +1,18 @@
{{- $external := strings.HasPrefix .link "http" -}}
{{- $activeClass := cond (.active) "active" "inactive" -}}
<a
class="hextra-sidebar-item-link {{ $activeClass }} [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] [word-break:break-word]"
href="{{ .link }}"
{{ if $external }}target="_blank" rel="noreferer"{{ end }}
>
{{- .title -}}
{{- with .context }}
{{- if or .RegularPages .Sections }}
{{- partialCached "components/sidebar/collapsible-button" . }}
{{- end }}
{{ end -}}
{{- with .items }}{{- partialCached "components/sidebar/collapsible-button" site.Home }}{{ end -}}
</a>

View File

@ -0,0 +1,16 @@
{{- $page := .page -}}
{{- $pageLink := $page.RelPermalink -}}
{{- $cached := .cached | default false }}
{{- range .data -}}
{{- $active := and (not $cached) (or (eq $pageLink .link) (eq (strings.TrimSuffix "/" $pageLink) .link)) -}}
{{- $containsPage := hasPrefix $pageLink .link -}}
{{- $shouldOpen := or (.open) $containsPage $active | default false -}}
<li class="hextra-sidebar-item {{ if $shouldOpen }}open{{ end }}">
{{- partial "components/sidebar/item-link" (dict "active" $active "title" .title "link" .link "items" .items) -}}
{{- if .items -}}
{{- partial "components/sidebar/render-items" (dict "items" .items "link" $pageLink "cached" $cached) -}}
{{- end -}}
</li>
{{ end }}

View File

@ -0,0 +1,21 @@
{{- $items := .items -}}
{{- $pageLink := .link -}}
{{- $cached := .cached | default false }}
<div class="ltr:hx-pr-0 hx-overflow-hidden">
<ul class="hextra-sidebar-item-list">
{{- range $items }}
{{- $active := and (not $cached) (or (eq $pageLink .link) (eq (strings.TrimSuffix "/" $pageLink) .link)) -}}
{{- $containsPage := hasPrefix $pageLink .link -}}
{{- $shouldOpen := or (.open) $containsPage $active | default false -}}
<li class="hextra-sidebar-item hx-flex hx-flex-col {{ if $shouldOpen }}open{{ end }}">
{{- partial "components/sidebar/item-link" (dict "active" $active "title" .title "link" .link "items" .items) -}}
{{- if .items -}}
{{- partial "components/sidebar/render-items" (dict "items" .items "link" $pageLink "cached" $cached) -}}
{{- end -}}
</li>
{{- end -}}
</ul>
</div>

View File

View File

@ -1,5 +1,7 @@
{{- $enableFooterSwitches := .Scratch.Get "enableFooterSwitches" | default false -}}
{{- $displayThemeToggle := site.Params.theme.displayToggle | default true -}}
{{- $footerSwitchesVisible := and $enableFooterSwitches (or hugo.IsMultilingual $displayThemeToggle) -}}
{{- $copyrightSectionVisible := or (.Site.Params.footer.displayPoweredBy | default true) .Site.Params.footer.displayCopyright -}}
{{- $copyright := (T "copyright") | default "© 2024 Hextra." -}}
{{- $poweredBy := (T "poweredBy") | default "Powered by Hextra" -}}
@ -15,7 +17,7 @@
<footer class="hextra-footer hx-bg-gray-100 hx-pb-[env(safe-area-inset-bottom)] dark:hx-bg-neutral-900 print:hx-bg-transparent">
{{- if $enableFooterSwitches -}}
{{- if $footerSwitchesVisible -}}
<div class="hx-mx-auto hx-flex hx-gap-2 hx-py-2 hx-px-4 {{ $footerWidth }}">
{{- partial "language-switch.html" (dict "context" .) -}}
{{- with $displayThemeToggle }}{{ partial "theme-toggle.html" }}{{ end -}}
@ -24,14 +26,21 @@
<hr class="dark:hx-border-neutral-800" />
{{- end -}}
{{- end -}}
<div
class="hextra-custom-footer {{ $footerWidth }} hx-pl-[max(env(safe-area-inset-left),1.5rem)] hx-pr-[max(env(safe-area-inset-right),1.5rem)] hx-text-gray-600 dark:hx-text-gray-400"
>
{{- partial "custom/footer.html" (dict "context" . "switchesVisible" $footerSwitchesVisible "copyrightVisible" $copyrightSectionVisible) -}}
</div>
{{- if $copyrightSectionVisible -}}
<div
class="{{ $footerWidth }} hx-mx-auto hx-flex hx-justify-center hx-py-12 hx-pl-[max(env(safe-area-inset-left),1.5rem)] hx-pr-[max(env(safe-area-inset-right),1.5rem)] hx-text-gray-600 dark:hx-text-gray-400 md:hx-justify-start"
>
<div class="hx-flex hx-w-full hx-flex-col hx-items-center sm:hx-items-start">
{{- if (.Site.Params.footer.displayPoweredBy | default true) }}<div class="hx-font-semibold">{{ template "theme-credit" $poweredBy }}</div>{{ end }}
{{- if .Site.Params.footer.displayCopyright }}<div class="hx-mt-6 hx-text-xs">{{ $copyright | markdownify }}</div>{{ end }}
{{- if (.Site.Params.footer.displayPoweredBy | default true) }}<div class="hx-font-semibold">{{ template "theme-credit" $poweredBy }}</div>{{- end -}}
{{- if .Site.Params.footer.displayCopyright }}<div class="hx-mt-6 hx-text-xs">{{ $copyright | markdownify }}</div>{{- end -}}
</div>
</div>
{{- end -}}
</footer>
{{- define "theme-credit" -}}

View File

@ -6,7 +6,7 @@
{{ else -}}
<meta name="robots" content="noindex, nofollow" />
{{ end -}}
{{ partialCached "favicons.html" . }}
{{ partialCached "favicons.html" . -}}
<title>
{{- if .IsHome -}}
{{ .Site.Title -}}
@ -17,17 +17,17 @@
</title>
<meta name="description" content="{{ partial "utils/page-description.html" . }}" />
{{ with .Params.canonical }}
{{- with .Params.canonical -}}
<link rel="canonical" href="{{ . }}" itemprop="url" />
{{ else }}
{{- else -}}
<link rel="canonical" href="{{ .Permalink }}" itemprop="url" />
{{ end }}
{{- end -}}
{{ partial "opengraph.html" . }}
{{ template "_internal/schema.html" . -}}
{{ template "_internal/twitter_cards.html" . -}}
{{- partial "opengraph.html" . -}}
{{- template "_internal/schema.html" . -}}
{{- template "_internal/twitter_cards.html" . -}}
{{ partialCached "head-css.html" . }}
{{- partialCached "head-css.html" . -}}
<!-- Google Analytics -->

View File

@ -42,7 +42,7 @@
{{/* Display icon menu item */}}
{{- if .Params.icon -}}
{{- $rel := cond (eq .Params.icon "mastodon") "noreferer me" "noreferer" }}
{{- $rel := cond (eq .Params.icon "mastodon") "noreferrer me" "noreferrer" }}
<a class="hx-p-2 hx-text-current" {{ if $external }}target="_blank" rel="{{ $rel }}"{{ end }} href="{{ $link }}" title="{{ or (T .Identifier) .Name | safeHTML }}">
{{- partial "utils/icon.html" (dict "name" .Params.icon "attributes" "height=24") -}}
<span class="hx-sr-only">{{ or (T .Identifier) .Name | safeHTML }}</span>
@ -53,7 +53,7 @@
<a
title="{{ or (T .Identifier) .Name | safeHTML }}"
href="{{ $link }}"
{{ if $external }}target="_blank" rel="noreferer"{{ end }}
{{ if $external }}target="_blank" rel="noreferrer"{{ end }}
class="hx-text-sm contrast-more:hx-text-gray-700 contrast-more:dark:hx-text-gray-100 hx-relative -hx-ml-2 hx-hidden hx-whitespace-nowrap hx-p-2 md:hx-inline-block {{ $activeClass }}"
>
<span class="hx-text-center">{{ or (T .Identifier) .Name | safeHTML }}</span>

View File

@ -4,7 +4,7 @@
{{- $jsLang := resources.Get "js/lang.js" -}}
{{- $jsCodeCopy := resources.Get "js/code-copy.js" -}}
{{- $jsFileTree := resources.Get "js/filetree.js" -}}
{{- $jsSidebar := resources.Get "js/sidebar.js" -}}
{{- $jsSidebar := resources.Get "js/sidebar.js" | resources.ExecuteAsTemplate "sidebar.js" . -}}
{{- $jsBackToTop := resources.Get "js/back-to-top.js" -}}
{{- $scripts := slice $jsTheme $jsMenu $jsCodeCopy $jsTabs $jsLang $jsFileTree $jsSidebar $jsBackToTop | resources.Concat "js/main.js" -}}
@ -37,9 +37,32 @@
{{- $mermaidJS := resources.Get "lib/mermaid/mermaid.min.js" | fingerprint -}}
<script defer src="{{ $mermaidJS.RelPermalink }}" integrity="{{ $mermaidJS.Data.Integrity }}"></script>
<script>
document.addEventListener("DOMContentLoaded", function () {
document.addEventListener("DOMContentLoaded", () => {
// Store original mermaid code for each diagram
document.querySelectorAll(".mermaid").forEach(el => {
el.dataset.original = el.innerHTML;
});
const theme = document.documentElement.classList.contains("dark") ? "dark" : "default";
mermaid.initialize({ startOnLoad: true, theme: theme });
let timeout;
new MutationObserver(() => {
clearTimeout(timeout);
timeout = setTimeout(() => {
const theme = document.documentElement.classList.contains("dark") ? "dark" : "default";
document.querySelectorAll(".mermaid").forEach(el => {
// Reset to original content, preserving HTML
el.innerHTML = el.dataset.original;
el.removeAttribute("data-processed");
});
mermaid.initialize({ startOnLoad: true, theme: theme });
mermaid.init();
}, 150);
}).observe(document.documentElement, {
attributes: true,
attributeFilter: ["class"]
});
});
</script>
{{- end -}}

View File

@ -2,6 +2,7 @@
{{- $type := .type -}}
{{- $class := .class | default "" -}}
{{- $border := .border | default false -}}
{{- $icon := .icon | default "" -}}
{{- $defaultClass := "hx-text-gray-600 hx-bg-gray-100 dark:hx-bg-neutral-800 dark:hx-text-neutral-200 hx-border-gray-200 dark:hx-border-neutral-700" -}}
{{- $warningClass := "hx-border-yellow-100 hx-bg-yellow-50 hx-text-yellow-900 dark:hx-border-yellow-200/30 dark:hx-bg-yellow-700/30 dark:hx-text-yellow-200" -}}
@ -11,6 +12,9 @@
{{- $borderClass := cond (eq $border true) "hx-border" "" -}}
{{- $badgeClass := cond (eq $type "info") $infoClass (cond (eq $type "warning") $warningClass (cond (eq $type "error") $errorClass $defaultClass)) -}}
<div class="hextra-badge {{ $class }}">
<div class="hx-inline-flex hx-items-center hx-rounded-full hx-px-2.5 hx-leading-6 hx-text-[.65rem] {{ $borderClass }} {{ $badgeClass }}">{{- $content -}}</div>
<div class="hx-inline-flex hx-gap-1 hx-items-center hx-rounded-full hx-px-2.5 hx-leading-6 hx-text-[.65rem] {{ $borderClass }} {{ $badgeClass }}">
{{- with $icon -}}{{- partial "utils/icon" (dict "name" . "attributes" "height=12") -}}{{- end -}}
{{- $content -}}
</div>
</div>
{{- /* Strip trailing newline. */ -}}

View File

@ -0,0 +1,28 @@
{{- $content := .content -}}
{{- $emoji := .emoji -}}
{{- $icon := .icon -}}
{{- $defaultClass := "hx-border-orange-100 hx-bg-orange-50 hx-text-orange-800 dark:hx-border-orange-400/30 dark:hx-bg-orange-400/20 dark:hx-text-orange-300" -}}
{{- $class := .class | default $defaultClass -}}
<div class="hx-overflow-x-auto hx-mt-6 hx-flex hx-rounded-lg hx-border hx-py-2 ltr:hx-pr-4 rtl:hx-pl-4 contrast-more:hx-border-current contrast-more:dark:hx-border-current {{ $class }}">
<div class="ltr:hx-pl-3 ltr:hx-pr-2 rtl:hx-pr-3 rtl:hx-pl-2">
{{- with $emoji -}}
<div class="hx-select-none hx-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="hx-inline-block hx-align-middle"`) -}}
{{- end -}}
{{- end -}}
</div>
<div class="hx-w-full hx-min-w-0 hx-leading-7">
<div class="hx-mt-6 hx-leading-7 first:hx-mt-0">
{{- $content -}}
</div>
</div>
</div>

View File

@ -3,48 +3,83 @@
{{- $disableSidebar := .disableSidebar | default false -}}
{{- $displayPlaceholder := .displayPlaceholder | default false -}}
{{/* EXPERIMENTAL - allow hiding sidebar on a per-page basis */}}
{{- if $context.Params.sidebar.hide -}}
{{- $disableSidebar = true -}}
{{- $displayPlaceholder = true -}}
{{- end -}}
{{- $sidebarClass := cond $disableSidebar (cond $displayPlaceholder "md:hx-hidden xl:hx-block" "md:hx-hidden") "md:hx-sticky" -}}
{{- $navRoot := cond (eq site.Home.Type "docs") site.Home $context.FirstSection -}}
{{- $pageURL := $context.RelPermalink -}}
{{/* EXPERIMENTAL */}}
{{- if .context.Params.sidebar.hide -}}
{{- $disableSidebar = true -}}
{{- $displayPlaceholder = true -}}
{{- $data := slice -}}
{{- $dataMobile := (partialCached "components/sidebar/generate-mobile-data" site.Home site.Home) | unmarshal -}}
{{- if (eq site.Params.page.sidebar.source "data") -}}
{{/* Get sidebar data from Hugo `data` directory */}}
{{- $data = partialCached "components/sidebar/get-section-data" $context $context.Section -}}
{{- else -}}
{{/* Generate and cache sidebar data in memory */}}
{{- $data = (partialCached "components/sidebar/generate-section-data" $navRoot $navRoot) | unmarshal -}}
{{- end -}}
{{/* Cache rendered sidebar */}}
{{- $shouldCache := site.Params.page.sidebar.cache | default false -}}
<div class="mobile-menu-overlay [transition:background-color_1.5s_ease] hx-fixed hx-inset-0 hx-z-10 hx-bg-black/80 dark:hx-bg-black/60 hx-hidden"></div>
<aside class="sidebar-container hx-flex hx-flex-col print:hx-hidden md:hx-top-16 md:hx-shrink-0 md:hx-w-64 md:hx-self-start max-md:[transform:translate3d(0,-100%,0)] {{ $sidebarClass }}">
<!-- Search bar on small screen -->
<div class="hx-px-4 hx-pt-4 md:hx-hidden">
{{ partial "search.html" }}
</div>
<aside class="hextra-sidebar-container hx-flex hx-flex-col print:hx-hidden md:hx-top-16 md:hx-shrink-0 md:hx-w-64 md:hx-self-start max-md:[transform:translate3d(0,-100%,0)] {{ $sidebarClass }}">
{{/* Search bar on small screen */}}
{{- partialCached "components/sidebar/mobile-search" . -}}
<div class="hextra-scrollbar hx-overflow-y-auto hx-overflow-x-hidden hx-p-4 hx-grow md:hx-h-[calc(100vh-var(--navbar-height)-var(--menu-height))]">
{{/* Mobile Navigation */}}
<ul class="hx-flex hx-flex-col hx-gap-1 md:hx-hidden">
<!-- Nav -->
{{ template "sidebar-main" (dict "context" site.Home "pageURL" $pageURL "page" $context "toc" true) -}}
{{ template "sidebar-footer" }}
{{- with $dataMobile -}}{{- partial "components/sidebar/render-data" (dict "data" . "page" $context) -}}{{- end -}}
</ul>
<!-- Sidebar on large screen -->
{{/* Sidebar on large screen */}}
{{- if $disableSidebar -}}
{{- if $displayPlaceholder }}<div class="max-xl:hx-hidden hx-h-0 hx-w-64 hx-shrink-0"></div>{{ end -}}
{{ .context.Scratch.Set "enableFooterSwitches" true }}
{{- else -}}
<ul class="hx-flex hx-flex-col hx-gap-1 max-md:hx-hidden">
{{ template "sidebar-main" (dict "context" $navRoot "page" $context "pageURL" $pageURL) }}
{{ template "sidebar-footer" }}
{{- with $data -}}
{{- if $shouldCache -}}
{{- partialCached "components/sidebar/render-data" (dict "data" . "page" $context "cached" $shouldCache) $navRoot -}}
{{- else -}}
{{- partial "components/sidebar/render-data" (dict "data" . "page" $context "cached" $shouldCache) -}}
{{- end -}}
{{- end -}}
{{- partialCached "components/sidebar/bottom" $context site.Home -}}
</ul>
{{ end -}}
<div style="position: absolute; top: 10px; right: 0; font-size: 10px; color: #888;">new</div>
</div>
{{- partial "components/sidebar/switches" (dict "context" $context "disableSidebar" $disableSidebar) -}}
</aside>
{{- define "partials/components/sidebar/mobile-search" -}}
<div class="hx-px-4 hx-pt-4 md:hx-hidden">
{{- partialCached "search.html" . -}}
</div>
{{- end -}}
{{- define "partials/components/sidebar/switches" -}}
{{- $context := .context -}}
{{- $disableSidebar := .disableSidebar -}}
{{/* Hide theme switch when sidebar is disabled */}}
{{ $switchesClass := cond $disableSidebar "md:hx-hidden" "" -}}
{{ $displayThemeToggle := (site.Params.theme.displayToggle | default true) -}}
{{ if or hugo.IsMultilingual $displayThemeToggle }}
<div class="{{ $switchesClass }} {{ with hugo.IsMultilingual }}hx-justify-end{{ end }} hx-sticky hx-bottom-0 hx-bg-white dark:hx-bg-dark hx-mx-4 hx-py-4 hx-shadow-[0_-12px_16px_#fff] hx-flex hx-items-center hx-gap-2 dark:hx-border-neutral-800 dark:hx-shadow-[0_-12px_16px_#111] contrast-more:hx-border-neutral-400 contrast-more:hx-shadow-none contrast-more:dark:hx-shadow-none hx-border-t" data-toggle-animation="show">
<div
class="{{ $switchesClass }} {{ with hugo.IsMultilingual -}}
hx-justify-end
{{- end }} hx-sticky hx-bottom-0 hx-bg-white dark:hx-bg-dark hx-mx-4 hx-py-4 hx-shadow-[0_-12px_16px_#fff] hx-flex hx-items-center hx-gap-2 dark:hx-border-neutral-800 dark:hx-shadow-[0_-12px_16px_#111] contrast-more:hx-border-neutral-400 contrast-more:hx-shadow-none contrast-more:dark:hx-shadow-none hx-border-t"
data-toggle-animation="show"
>
{{- with hugo.IsMultilingual -}}
{{- partial "language-switch" (dict "context" $context "grow" true) -}}
{{- with $displayThemeToggle }}{{ partial "theme-toggle" (dict "hideLabel" true) }}{{ end -}}
@ -55,124 +90,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] hx-mt-5 hx-mb-2 hx-px-2 hx-py-1.5 hx-text-sm hx-font-semibold hx-text-gray-900 first:hx-mt-0 dark:hx-text-gray-100">
<span class="hx-cursor-default">{{ partial "utils/title" . }}</span>
</li>
{{- else -}}
{{- $active := eq $pageURL .RelPermalink -}}
{{- $shouldOpen := or (.Params.sidebar.open) (.IsAncestor $page) $active | default true }}
<li class="{{ if $shouldOpen }}open{{ end }}">
{{- $linkTitle := partial "utils/title" . -}}
{{- 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:hx-pr-0 hx-overflow-hidden">
<ul class='hx-relative hx-flex hx-flex-col hx-gap-1 before:hx-absolute before:hx-inset-y-1 before:hx-w-px before:hx-bg-gray-200 before:hx-content-[""] ltr:hx-ml-3 ltr:hx-pl-3 ltr:before:hx-left-0 rtl:hx-mr-3 rtl:hx-pr-3 rtl:before:hx-right-0 dark:before:hx-bg-neutral-800'>
{{- range $items.ByWeight }}
{{- $active := eq $pageURL .RelPermalink -}}
{{- $shouldOpen := or (.Params.sidebar.open) (.IsAncestor $page) $active | default true }}
{{- $linkTitle := partial "utils/title" . -}}
<li class="hx-flex hx-flex-col {{ 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 -}}
</ul>
</div>
{{- end -}}
{{- end }}
{{- end -}}
{{- define "sidebar-toc" -}}
{{ $page := .page }}
{{ with $page.Fragments.Headings }}
<ul class='hx-flex hx-flex-col hx-gap-1 hx-relative before:hx-absolute before:hx-inset-y-1 before:hx-w-px before:hx-bg-gray-200 before:hx-content-[""] dark:before:hx-bg-neutral-800 ltr:hx-pl-3 ltr:before:hx-left-0 rtl:hx-pr-3 rtl:before:hx-right-0 ltr:hx-ml-3 rtl:hx-mr-3'>
{{- range . }}
{{- with .Headings }}
{{- range . -}}
<li>
<a
href="#{{ anchorize .ID }}"
class="hx-flex hx-rounded hx-px-2 hx-py-1.5 hx-text-sm hx-transition-colors [word-break:break-word] hx-cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:hx-border hx-gap-2 before:hx-opacity-25 before:hx-content-['#'] hx-text-gray-500 hover:hx-bg-gray-100 hover:hx-text-gray-900 dark:hx-text-neutral-400 dark:hover:hx-bg-primary-100/5 dark:hover:hx-text-gray-50 contrast-more:hx-text-gray-900 contrast-more:dark:hx-text-gray-50 contrast-more:hx-border-transparent contrast-more:hover:hx-border-gray-900 contrast-more:dark:hover:hx-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] hx-mt-5 hx-mb-2 hx-px-2 hx-py-1.5 hx-text-sm hx-font-semibold hx-text-gray-900 first:hx-mt-0 dark:hx-text-gray-100">
<span class="hx-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="hx-flex hx-items-center hx-justify-between hx-gap-2 hx-cursor-pointer hx-rounded hx-px-2 hx-py-1.5 hx-text-sm hx-transition-colors [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] [word-break:break-word]
{{- if .active }}
sidebar-active-item hx-bg-primary-100 hx-font-semibold hx-text-primary-800 contrast-more:hx-border contrast-more:hx-border-primary-500 dark:hx-bg-primary-400/10 dark:hx-text-primary-600 contrast-more:dark:hx-border-primary-500
{{- else }}
hx-text-gray-500 hover:hx-bg-gray-100 hover:hx-text-gray-900 contrast-more:hx-border contrast-more:hx-border-transparent contrast-more:hx-text-gray-900 contrast-more:hover:hx-border-gray-900 dark:hx-text-neutral-400 dark:hover:hx-bg-primary-100/5 dark:hover:hx-text-gray-50 contrast-more:dark:hx-text-gray-50 contrast-more:dark:hover:hx-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="hx-h-[18px] hx-min-w-[18px] hx-rounded-sm hx-p-0.5 hover:hx-bg-gray-800/5 dark:hover:hx-bg-gray-100/5"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" class="hx-origin-center hx-transition-transform rtl:-hx-rotate-180"></path></svg>
{{- end -}}

View File

@ -38,7 +38,7 @@
{{- $editURL = urls.JoinPath $editURL $sourceDir $path -}}
{{- end -}}
{{- end -}}
<a class="hx-text-xs hx-font-medium hx-text-gray-500 hover:hx-text-gray-900 dark:hx-text-gray-400 dark:hover:hx-text-gray-100 contrast-more:hx-text-gray-800 contrast-more:dark:hx-text-gray-50" href="{{ $editURL }}" target="_blank" rel="noreferer">{{ $editThisPage }}</a>
<a class="hx-text-xs hx-font-medium hx-text-gray-500 hover:hx-text-gray-900 dark:hx-text-gray-400 dark:hover:hx-text-gray-100 contrast-more:hx-text-gray-800 contrast-more:dark:hx-text-gray-50" href="{{ $editURL }}" target="_blank" rel="noreferrer">{{ $editThisPage }}</a>
{{- end -}}
{{/* Scroll To Top */}}
<button aria-hidden="true" id="backToTop" onClick="scrollUp();" class="hx-transition-all hx-duration-75 hx-opacity-0 hx-text-xs hx-font-medium hx-text-gray-500 hover:hx-text-gray-900 dark:hx-text-gray-400 dark:hover:hx-text-gray-100 contrast-more:hx-text-gray-800 contrast-more:dark:hx-text-gray-50">

View File

@ -0,0 +1,17 @@
{{/*
Utility to retrieve a translated page given a page and a language code.
If the page is not translated, it returns the original page.
*/}}
{{- $page := .page -}}
{{- $lang := .lang -}}
{{- if $page.IsTranslated -}}
{{- range $page.AllTranslations -}}
{{- if eq .Language.LanguageCode $lang -}}
{{- $page = . -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{- return $page -}}

View File

@ -3,6 +3,7 @@
{{- $type := .Get "type" | default "" -}}
{{- $class := .Get "class" | default "" -}}
{{- $link := .Get "link" | default "" -}}
{{- $icon := .Get "icon" | default "" -}}
{{- if $link -}}
<a href="{{ $link }}" title="{{ $content | plainify }}" target="_blank">
@ -11,6 +12,7 @@
"type" $type
"class" $class
"border" true
"icon" $icon
)
-}}
</a>
@ -20,6 +22,7 @@
"type" $type
"class" $class
"border" true
"icon" $icon
)
-}}
{{- end -}}

View File

@ -1,37 +1,19 @@
{{ $calloutEmojiDict := dict "info" "" "warning" "⚠️" "error" "🚫" }}
{{ $type := .Get "type" | default "default" }}
{{- $calloutEmojiDict := dict "info" "" "warning" "⚠️" "error" "🚫" -}}
{{- $type := .Get "type" | default "default" -}}
{{/* If emoji is not set, use the emoji from dict */}}
{{ $emoji := .Get "emoji" }}
{{ if eq $emoji "" }}
{{ $emoji = index $calloutEmojiDict $type }}
{{ end }}
{{- $emoji := .Get "emoji" -}}
{{- if eq $emoji "" -}}
{{- $emoji = index $calloutEmojiDict $type -}}
{{- end -}}
{{/* Also allow using "icon" */}}
{{ $icon := .Get "icon" }}
{{- $icon := .Get "icon" -}}
{{- $content := .InnerDeindent | markdownify -}}
{{ $defaultClass := "hx-border-orange-100 hx-bg-orange-50 hx-text-orange-800 dark:hx-border-orange-400/30 dark:hx-bg-orange-400/20 dark:hx-text-orange-300" }}
{{ $infoClass := "hx-border-blue-200 hx-bg-blue-100 hx-text-blue-900 dark:hx-border-blue-200/30 dark:hx-bg-blue-900/30 dark:hx-text-blue-200" }}
{{ $warningClass := "hx-border-yellow-100 hx-bg-yellow-50 hx-text-yellow-900 dark:hx-border-yellow-200/30 dark:hx-bg-yellow-700/30 dark:hx-text-yellow-200" }}
{{ $errorClass := "hx-border-red-200 hx-bg-red-100 hx-text-red-900 dark:hx-border-red-200/30 dark:hx-bg-red-900/30 dark:hx-text-red-200" }}
{{- $defaultClass := "hx-border-orange-100 hx-bg-orange-50 hx-text-orange-800 dark:hx-border-orange-400/30 dark:hx-bg-orange-400/20 dark:hx-text-orange-300" -}}
{{- $infoClass := "hx-border-blue-200 hx-bg-blue-100 hx-text-blue-900 dark:hx-border-blue-200/30 dark:hx-bg-blue-900/30 dark:hx-text-blue-200" -}}
{{- $warningClass := "hx-border-yellow-100 hx-bg-yellow-50 hx-text-yellow-900 dark:hx-border-yellow-200/30 dark:hx-bg-yellow-700/30 dark:hx-text-yellow-200" -}}
{{- $errorClass := "hx-border-red-200 hx-bg-red-100 hx-text-red-900 dark:hx-border-red-200/30 dark:hx-bg-red-900/30 dark:hx-text-red-200" -}}
{{ $class := cond (eq $type "info") $infoClass (cond (eq $type "warning") $warningClass (cond (eq $type "error") $errorClass $defaultClass)) }}
{{- $class := cond (eq $type "info") $infoClass (cond (eq $type "warning") $warningClass (cond (eq $type "error") $errorClass $defaultClass)) -}}
<div class="hx-overflow-x-auto hx-mt-6 hx-flex hx-rounded-lg hx-border hx-py-2 ltr:hx-pr-4 rtl:hx-pl-4 contrast-more:hx-border-current contrast-more:dark:hx-border-current {{ $class }}">
<div class="ltr:hx-pl-3 ltr:hx-pr-2 rtl:hx-pr-3 rtl:hx-pl-2">
{{- with $emoji -}}
<div class="hx-select-none hx-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="hx-inline-block hx-align-middle"`) -}}
{{- end -}}
{{- end -}}
</div>
<div class="hx-w-full hx-min-w-0 hx-leading-7">
<div class="hx-mt-6 hx-leading-7 first:hx-mt-0">
{{ .InnerDeindent | markdownify }}
</div>
</div>
</div>
{{- partial "shortcodes/callout.html" (dict "content" $content "emoji" $emoji "icon" $icon "class" $class) -}}

View File

@ -0,0 +1,10 @@
{{- $style := .Get "style" -}}
{{- $heading := int (strings.TrimPrefix "h" (.Get "heading" | default "h2")) -}}
{{- $size := cond (ge $heading 4) "xl" (cond (eq $heading 3) "2xl" "4xl") -}}
<h{{ $heading }}
class="not-prose hx-text-{{ $size }} hx-font-bold hx-leading-none hx-tracking-tighter md:hx-text-3xl hx-py-2 hx-bg-clip-text hx-text-transparent hx-bg-gradient-to-r hx-from-gray-900 hx-to-gray-600 dark:hx-from-gray-100 dark:hx-to-gray-400"
{{ with $style }}style="{{ . | safeCSS }}"{{ end }}
>
{{ .Inner | markdownify }}
</h{{ $heading }}>

View File

@ -9,7 +9,7 @@
<div class="hx-mt-4 hx-flex hx-w-max hx-min-w-full hx-border-b hx-border-gray-200 hx-pb-px dark:hx-border-neutral-800">
{{- range $i, $item := $items -}}
<button
class="hextra-tabs-toggle data-[state=selected]:hx-border-primary-500 data-[state=selected]:hx-text-primary-600 hx-mr-2 hx-rounded-t hx-p-2 hx-font-medium hx-leading-5 hx-transition-colors -hx-mb-0.5 hx-select-none hx-border-b-2 hx-border-transparent hx-text-gray-600 hover:hx-border-gray-200 hover:hx-text-black dark:hx-text-gray-200 dark:hover:hx-border-neutral-800 dark:hover:hx-text-white"
class="hextra-tabs-toggle data-[state=selected]:hx-border-primary-500 data-[state=selected]:hx-text-primary-600 data-[state=selected]:dark:hx-border-primary-500 data-[state=selected]:dark:hx-text-primary-600 hx-mr-2 hx-rounded-t hx-p-2 hx-font-medium hx-leading-5 hx-transition-colors -hx-mb-0.5 hx-select-none hx-border-b-2 hx-border-transparent hx-text-gray-600 hover:hx-border-gray-200 hover:hx-text-black dark:hx-text-gray-200 dark:hover:hx-border-neutral-800 dark:hover:hx-text-white"
role="tab"
type="button"
aria-controls="tabs-panel-{{ $i }}"

View File

@ -7,6 +7,6 @@ command = "cd exampleSite && hugo --gc --minify --themesDir ../.. -b ${DEPLOY_PR
ignore = "false"
[build.environment]
HUGO_VERSION = "0.132.2"
HUGO_VERSION = "0.138.0"
GO_VERSION = "1.22.3"
NODE_VERSION = "22.2.0"

14
package-lock.json generated
View File

@ -523,11 +523,10 @@
}
},
"node_modules/cross-spawn": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
"dev": true,
"license": "MIT",
"dependencies": {
"path-key": "^3.1.0",
"shebang-command": "^2.0.0",
@ -1031,9 +1030,9 @@
}
},
"node_modules/nanoid": {
"version": "3.3.7",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
"integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
"version": "3.3.8",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz",
"integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==",
"dev": true,
"funding": [
{
@ -1041,7 +1040,6 @@
"url": "https://github.com/sponsors/ai"
}
],
"license": "MIT",
"bin": {
"nanoid": "bin/nanoid.cjs"
},

View File

@ -61,8 +61,11 @@ module.exports = {
neutral: colors.neutral,
red: colors.red,
orange: colors.orange,
green: colors.green,
indigo: colors.indigo,
blue: colors.blue,
yellow: colors.yellow,
amber: colors.amber,
primary: {
50: makePrimaryColor(97),
100: makePrimaryColor(94),