Compare commits

..

84 Commits

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

Light / dark theme can be configured via:

```yaml
  theme:
    # light | dark | system
    default: system
    displayToggle: true
```
2023-10-21 22:18:04 +01:00
Xin
93cb788e52 feat(search): support different search index types (#145)
* add support for different search index types: `content | summary | heading | title`
* resolves #139
2023-10-21 21:00:39 +01:00
88b0f1b2ab fix: broken "edit this page" link in windows (#143) 2023-10-18 22:33:36 +01:00
a31b46f5e3 chore(i18n): add translations of Korean (#144)
* chore(i18n): add translations of Korean

* Update ko.yaml

---------

Co-authored-by: Xin <xin@imfing.com>
2023-10-18 22:32:28 +01:00
Sid
6641d36b98 docs: add using Hextra as Git submodule (#137)
* docs: update docs relating to getting started and Hugo modules

* docs: add docs to use Hextra as Git submodule, closes #107

* chore: use paragraph instead of callout, refactor docs

* Update getting-started.md

* Update getting-started.md

---------

Co-authored-by: Xin <xin@imfing.com>
2023-10-16 14:28:28 +01:00
e42d01898a fix: add missing translations (#142)
* fix: add missing translation in blog list

* fix: add translatable variables

* Update en.yaml

---------

Co-authored-by: Xin <xin@imfing.com>
2023-10-16 13:30:31 +01:00
Xin
6cd4c55613 fix: callout styling issue with markdown content (#141) 2023-10-13 00:09:57 +01:00
Xin
cb09b7ce1e fix: skip scroll event if no backToTop element (#138) 2023-10-12 23:25:34 +01:00
96c6ff073f chore(i18n): update zh-cn.yaml (#136) 2023-10-11 23:22:07 +01:00
Xin
28a20e1e7e chore: add code copy button icons in js (#133) 2023-10-07 20:01:19 +01:00
Xin
5f4c7423d0 chore: add feature request issue template
[skip ci]
2023-10-04 20:54:29 +01:00
Xin
2bc4ed19e3 chore: add issue bug report template
[skip ci]
2023-10-04 20:51:22 +01:00
Xin
8aa6439132 feat: support custom primary saturation (#131)
* feat: support custom primary saturation

* chore: run npm run build:css

* docs: update instruction for customizing primary color
2023-10-04 20:41:59 +01:00
b7558aca44 feat: support empty prev/next pagination (#130)
[skip ci]
2023-10-04 20:13:49 +01:00
Xin
55ff819dae fix: not-prose p tag inconsistent style (#126)
* fix: not-prose p tag should reset styles

* chore: compile CSS
2023-10-03 09:12:30 +01:00
Xin
924d8508d0 fix: footer enable flag logic issue (#125) 2023-10-03 08:51:41 +01:00
1b932f260a chore: add Vietnamese translation (#123)
[skip ci]
2023-10-03 08:36:35 +01:00
5768ed4695 chore: add Portuguese translation (#119) 2023-10-02 23:53:53 +01:00
f4cea168b1 chore: spanish translations es.yaml (#114)
[skip ci]
2023-10-02 11:57:12 +01:00
e2d00fdcd0 chore: add Swahili translation (#113)
[skip ci]
2023-10-01 23:13:18 +01:00
Xin
103faa24f3 chore: re-compile CSS 2023-10-01 09:25:02 +00:00
d1bed05843 feat: Back To Top (#105)
* Scroll to top

* Update scripts.html

---------

Co-authored-by: Xin <xin@imfing.com>
2023-10-01 10:06:28 +01:00
Xin
2df3c563bf fix: use div for copyright container in footer (#104) 2023-09-27 20:40:35 +01:00
Xin
ec02eb34fe fix: search shortcut based on user platform (#101)
* fix: search shortcut based on user platform

* chore: make it work with iPad and iPhone as well
2023-09-27 19:47:20 +01:00
Xin
46dea718e6 docs: add giscus comments system (#96)
* chore: rename comment to comments

* docs: add giscus comments

* docs: update
2023-09-26 23:33:27 +01:00
Xin
adf5a113fc fix: giscus theme and language display issues (#95)
* chore: minor update giscus template

* fix: theme toggle should select all

* chore: example configs for giscus

* fix: language code in giscus
2023-09-26 22:12:38 +01:00
6a19ac31c0 feat: add giscus support (#92)
* feat: add giscus support #89

* Update comment.html

* Update giscus.html

* Update giscus.html

---------

Co-authored-by: Xin <xin@imfing.com>
2023-09-26 20:47:22 +01:00
Xin
3c4ede96df feat: add shortcodes to build Hextra home page (#90)
* feat: add feature grid and card shortcodes

* feat: add markdown content to hextra home

* chore: add button for hextra home

* chore: add heading and subtitle

* chore: finish moving hextra home to shortcodes

* chore: regenerate css

* chore: improve hextra home layout shortcodes

* chore: update css

* chore: decrease button size
2023-09-26 08:15:31 +01:00
Xin
01f7e3a425 docs: add showcase page (#86)
* docs: add showcase page

* chore: update compiled CSS

* chore: add showcase to navbar

* chore: reorder show case on navbar

* chore: update card image style

* chore: update showcase images

* chore: update showcase card image
2023-09-24 15:30:17 +01:00
da5a087891 fix: reverse order in blog list page (#87)
* feat: support reverse order in blog list page

* chore: update blog list order

---------

Co-authored-by: Xin <xin@imfing.com>
2023-09-24 14:54:38 +01:00
Xin
79883dc7cc fix: process static image url correctly 2023-09-24 11:03:34 +01:00
Xin
b283227046 feat: enhance image resolving (#82)
* feat: enhance image resolving

* chore: don't process image path that begins with relative link

* docs: add instruction for adding images

* chore: update docs

* chore: add filenames to images docs
2023-09-23 23:54:17 +01:00
Xin
0e9cf1a519 fix: add integrity attribute to styles css preload tag (#83) 2023-09-23 22:42:05 +01:00
Xin
fdc30c6cd5 fix: card image not displaying correctly (#77)
* fix: use relative URL for card images

* chore: update card image processing

* chore: add width and height for process image

* docs: update cards docs
2023-09-23 19:25:51 +01:00
Xin
3632294706 chore: update list page RSS template (#75)
* chore: update RSS feed template

* chore: use html instead of safeHTML
2023-09-22 23:41:53 +01:00
929578192b fix: htmlUnescape page description (#71)
- add htmlUnescape
2023-09-21 22:46:08 +01:00
Sid
c18d5def26 ci: upgrade actions/checkout from v3 to v4 (#73)
https://github.com/actions/checkout#checkout-v4
2023-09-21 21:42:15 +01:00
Xin
4e63aa4f14 feat: add google analytics support (#70)
* feat: support google analytics

* docs: add instruction for setting up ga
2023-09-21 08:03:35 +01:00
Xin
b51bfa3177 feat: support wide and full page modes (#69)
* feat: add page width config and partial

* feat: use page-width partial in layouts

* chore: revert changes in navbar and footer

* feat: customize footer width from site config

* chore: update styles

* docs: add page width

* feat: allow overriding navbar width

* fix: navbar width variable

* docs: add instruction for navbar and footer
2023-09-20 23:36:00 +01:00
c799160e86 feat: add native image processing to cards (#63)
* Add native image processing to cards

* feat: Image processing options, markdown subtitles

* fixing a type

* Public Domain Images

* image height fix

* Smaller Image

* Removed fullwidth param

* Smaller image from unsplash

* Replaced static image as well

* Update single.html

* Update list.html

* Update list.html

* Update single.html

* Update list.html

* Update single.html

* Update cards.md

* Update cards.md

---------

Co-authored-by: Xin <xin@imfing.com>
2023-09-19 00:04:48 +01:00
00d26dee2c fix: swap navbar logo width and height (#58)
Height/Width swap issue.
2023-09-14 08:17:28 +01:00
Xin
e9ea9786e9 feat: enhance scrollbar style (#56)
* feat: enhance scrollbar style

* chore: set `color-scheme` for document element
2023-09-14 00:01:38 +01:00
84ac7fe773 docs: add example for customizing css for inline code element (#55)
* discussion #40

* discussion #46

* corrected Go code

* removed code block section

* changed heading to 'Inline Code Element'

---------

Co-authored-by: Saurabh Mishra <saurabh.m@mailfence.com>
2023-09-13 22:34:46 +01:00
Xin
a184cfd41e fix: use relURL only for link starts with slash (#54) 2023-09-13 05:40:00 -04:00
Xin
76ac694542 feat: add backdrop blur for nav bar (#53) 2023-09-13 10:02:38 +01:00
Xin
f70ba59ca0 fix: use relative url for card link (#52)
* fix: cards links should not redirect to 404

* docs: update card links

* fix: use relURL for card link
2023-09-13 09:49:01 +01:00
Xin
4a9a2850fc docs: add instruction for using markdown in tabs (#47) 2023-09-13 07:54:44 +01:00
Xin
4553a8eda2 docs: add more instruction for favicon (#44) 2023-09-11 17:15:24 -04:00
Xin
237d890f67 ci: use dynamic repo and username for baseURL 2023-09-10 15:20:17 +01:00
Xin
04e131f93a chore: normalize headings (#42)
* chore: minor update to card component

* chore: normalize headings of blog and single page
2023-09-10 14:54:30 +01:00
Xin
61e41f247b chore: add contributing guide
[skip ci]
2023-09-10 12:07:04 +01:00
6d00cb32b0 docs: add Logo, Favicon in Configurations (#37)
* Add Configuration for Logo, Favicon.

---------

Co-authored-by: Xin <xin@imfing.com>
2023-09-05 23:45:05 +01:00
939acc02a8 fix: add line break for steps shortcode example usage
* there needs to be a line break between {{% steps %}} and the first H3

If there is no line break between {{% steps %}}  and the first heading, the content is not rendered correctly.

* Update exampleSite/content/docs/guide/shortcodes/steps.md

* Update exampleSite/content/docs/guide/shortcodes/steps.md
2023-09-05 06:24:51 -04:00
Sid
e4c36236df ci: setup actions/checkout@v3 to fetch complete Git history (#32)
Attempt to fix #31
2023-09-03 19:05:33 +01:00
Xin
4381f31085 chore: make index page container wider (#30)
* chore: enable footer by default

* chore: make index container wider
2023-09-03 16:12:53 +01:00
Xin
171399889d docs: add instruction to update theme 2023-09-02 16:02:28 +01:00
Xin
3bcdf84ad4 feat: details shortcode (#28)
* feat: details shortcode

* docs: add details shortcode page

* chore: update shortcodes page

* docs: update

* Revert "chore: update shortcodes page"

This reverts commit c005ad4cb1.
2023-09-02 16:01:34 +01:00
Xin
8e8f7f23c9 chore: increase home heading text line height 2023-09-02 00:10:51 +00:00
Xin
5b71912ab2 feat: support markdown for copyright text (#25)
* feat: support markdown for copyright text

* docs: add info about supporting markdown in copyright
2023-09-01 22:38:49 +01:00
34c6f6c7f3 docs: added info to configure footer (#23) 2023-09-01 22:19:14 +01:00
Xin
8a4e093f12 fix: toc should display headings as is (#20) 2023-09-01 00:34:50 +01:00
Xin
ed14cf01c3 chore: update local dev config
[skip ci]
2023-08-31 20:49:28 +01:00
Xin
b709452d16 chore(i18n): improve translations of zh-cn (#14) 2023-08-30 21:35:04 +01:00
e1a2109a68 i18n: Add some zh-cn translation of exampleSite(docs) (#12)
---------

Co-authored-by: Xin <xin@imfing.com>
2023-08-30 21:21:31 +01:00
392c6f8dde current instructions show a 404 and pages dont render correctly (#10) 2023-08-30 08:11:40 +01:00
7993dc3230 i18n: Add translation of zh-cn and zh-hk (#8)
* Add translation of zh-cn

* Add translation of zh-hk

---------
Co-authored-by: Xin <xin@imfing.com>
2023-08-29 20:57:44 +01:00
Xin
b96eb01af3 docs: enchance pages navigation 2023-08-28 22:45:29 +01:00
Xin
e1fa9e73d2 chore: replace space with nbsp 2023-08-28 22:32:50 +01:00
Xin
c0d15f89e8 chore: proper dev and prod styles handling 2023-08-28 22:32:07 +01:00
116 changed files with 4283 additions and 2533 deletions

110
.github/CONTRIBUTING.md vendored Normal file
View File

@ -0,0 +1,110 @@
# Contribute to Hextra
👋 Thank you for being interested in contributing to Hextra! As an open source project, we welcome contributions of many forms including bug reports, feature requests, documentation improvements, and code contributions.
<!-- omit in toc -->
## Table of Contents
- [Guidelines](#guidelines)
- [Contributing Code](#contributing-code)
- [Contributing Documentation](#contributing-documentation)
- [💬 GitHub Discussions](#-github-discussions)
- [GitHub Issues](#github-issues)
- [Development](#development)
- [Local development setup](#local-development-setup)
- [Project structure](#project-structure)
- [Start the development server](#start-the-development-server)
- [Compile the styles](#compile-the-styles)
## Guidelines
### Contributing Code
To contribute, please follow the ["Fork and Pull Request"][fork and pull] workflow
Fork the repository, make your changes, and then submit a pull request.
Please make sure to include a description of the changes you made and why you made them.
Use [Conventional Commits][conventional commits] message to make it easier to understand the changes you made.
### Contributing Documentation
Similar to contributing code, you can also contribute to the documentation by submitting a pull request.
The documentation site is located in the [`exampleSite`](../exampleSite/) folder.
You can make changes to the documentation and create a pull request. A preview of the new documentation will be automatically generated and displayed in the pull request comment via [Netlify][netlify deploy preview].
### 💬 GitHub Discussions
Were using [Discussions][discussions] as a place to connect with other members using Hextra:
- Ask questions youre wondering about.
- Share ideas.
- Engage with other users.
### GitHub Issues
If you find a bug or have a feature request, please [open an issue][issues].
Please make sure to include a description of the bug or feature you are requesting. If you are reporting a bug, please include steps to reproduce the bug.
We recommend that you search existing [issues][issues] or discussions before opening a new one to prevent duplicates.
## Development
> **Note**
> You can start developing on [GitHub Codespaces][open in codespaces] or use [devcontainer][devcontainer] locally without installing any dependencies.
### Local development setup
- [Hugo][hugo] >= v0.115.0 (extended version)
- [Node.js][nodejs]
- [Go][go]
Install dependencies:
```bash
npm i
```
### Project structure
- [`assets`](../assets/): CSS styles and JavaScript files.
- [`data`](../data/): The theme data files. Now only contains the `icons.yaml` file.
- [`exampleSite`](../exampleSite/): The documentation site for the theme.
- [`i18n`](../i18n/): The theme translation files.
- [`layouts`](../layouts/): The theme layouts.
- [`static`](../static/): The static files for the theme. For example, the favicon and the site logo.
Please refer to the [Hugo documentation][hugo] for more information.
### Start the development server
```bash
npm run dev:theme
```
It will start the Hugo server on `http://localhost:1313/` for the `exampleSite` content.
### Compile the styles
For development preview, we compile the Tailwind CSS styles on the fly. But for production, we need to compile the styles first.
```bash
npm run build:css
```
It will compile the Tailwind CSS styles and generate the `assets/css/compiled/main.css` file.
<!--links-->
[fork and pull]: https://docs.github.com/en/get-started/quickstart/contributing-to-projects
[conventional commits]: https://www.conventionalcommits.org
[issues]: https://github.com/imfing/hextra/issues
[discussions]: https://github.com/imfing/hextra/discussions
[nodejs]: https://nodejs.org/en/
[hugo]: https://gohugo.io/
[go]: https://golang.org/doc/install
[devcontainer]: https://code.visualstudio.com/docs/devcontainers/containers
[open in codespaces]: https://codespaces.new/imfing/hextra
[netlify deploy preview]: https://docs.netlify.com/site-deploys/deploy-previews/

40
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@ -0,0 +1,40 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Description**
<!-- Provide a clear and concise description of the bug -->
**Steps To Reproduce**
1.
2.
3.
**Expected Behavior**
<!-- What should have happened? -->
**Actual Behavior**
<!-- What happened instead? -->
**Screenshots**
<!-- If applicable, add screenshots to help explain your problem -->
**Environment**
- Hugo Version: [e.g., 0.85.0]
- Browser/OS: [e.g., Chrome, MacOS]
- Theme Version: [e.g., v2.0]
**Additional Context**
<!-- Add any other context about the problem here -->

View File

@ -0,0 +1,24 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**Feature Description**
<!-- Provide a clear and concise description of the feature -->
**Problem/Solution**
<!-- What problem will this feature solve? Or what new capability will it add? -->
**Alternatives Considered**
<!-- Have you considered any alternative solutions or workarounds? -->
**Additional Context**
<!-- Add any other context or screenshots about the feature request here -->

View File

@ -34,7 +34,9 @@ jobs:
HUGO_VERSION: 0.117.0
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 0 # Fetch all history for .GitInfo and .Lastmod
- name: Setup Go
uses: actions/setup-go@v4
with:
@ -53,7 +55,7 @@ jobs:
hugo \
--minify \
--themesDir=../.. --source=exampleSite \
--baseURL "https://imfing.github.io/hextra/"
--baseURL "https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/"
- name: Upload artifact
uses: actions/upload-pages-artifact@v2
with:

View File

@ -1,4 +1,5 @@
{
"editor.tabSize": 2,
"css.customData": [".vscode/tailwind.json"]
"css.customData": [".vscode/tailwind.json"],
"markdown.extension.toc.levels": "2..6"
}

View File

@ -31,13 +31,16 @@ Using the [Hextra Starter Template](https://github.com/imfing/hextra-starter-tem
The template repository also includes a [GitHub Actions workflow](https://docs.github.com/en/pages/getting-started-with-github-pages/configuring-a-publishing-source-for-your-github-pages-site#publishing-with-a-custom-github-actions-workflow) for deploying your website to GitHub Pages.
<img alt="Hextra Starter Template" src="https://user-images.githubusercontent.com/5097752/263551418-c403b9a9-a76c-47a6-8466-513d772ef0b7.jpg" width=600/>
### Usage
Refer to the [documentation](https://imfing.github.io/hextra/docs) for more information.
## Contributing
This project is actively under development. Contributions are welcome!
Contributions are welcome!
Check out the [contributing guide](.github/CONTRIBUTING.md) to get started.
## License

44
README.zh-cn.md Normal file
View File

@ -0,0 +1,44 @@
<div align="center">
<h1 align="center">Hextra</h1>
<p align="center">用于创建美观的静态站点的现代化, 响应式, 功能强大的 Hugo 主题.</p>
演示 → [imfing.github.io/hextra](https://imfing.github.io/hextra/)
</div>
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://user-images.githubusercontent.com/5097752/263550533-c18343ca-3848-4230-b5c0-ee989d7916da.png">
<img alt="Hextra" src="https://user-images.githubusercontent.com/5097752/263550528-663599f9-17a1-4686-b5c4-3da233b5034d.png">
</picture>
<div align="right">
<a href="https://github.com/imfing/hextra/actions/workflows/pages.yml"><img alt="GitHub Actions Status" src="https://github.com/imfing/hextra/actions/workflows/pages.yml/badge.svg"></a> <a href="https://app.netlify.com/sites/hugo-hextra/deploys"><img alt="Netlify Status" src="https://api.netlify.com/api/v1/badges/61d6e55a-2447-487e-b59f-c9537e5df175/deploy-status"></a>
</div>
## 特性
- **美观的设计** - 受 Nextra 的启发Hextra 利用 Tailwind CSS 提供现代化的设计,使您的网站看起来美观有加.
- **响应式布局和深色模式支持** - 在任何设备上看起来都足够美观, 无论是手机, 平板电脑或者电脑. 深色模式的支持使 Hextra 可以应对各种照明环境.
- **快速且轻量** - 由 Hugo 强力支持, Hugo 是一个快如闪电的静态站点生成器, 这一切都只需一个可执行文件, Hextra 始终保持最小化, 无需 Javascript 或者 Node.js.
- **全文搜索** - 集成了 Flexsearch 的全文搜索, 无需额外的配置.
- **网站中的瑞士军刀** - Markdown, 代码高亮, LaTex 数学公式, diagrams 图表和 Shortcodes 都可以用于丰富你的内容. 目录, 面包屑导航, 分页, 侧边栏等均由 Hextra 自动生成。
- **多语言和 SEO Ready** - Hugo 的多语言模式使得构建多语言网站更简单. 具有 SEO tags, Open Graph, 和 Twitter Cards 等诸多开箱即用的功能.
## 快速开始
### 使用模板
使用 [Hextra stater template](https://github.com/imfing/hextra-starter-template) 是使用 Hextra 主题的最简单方法. 点击仓库页面上的 `Use this template` 按钮开始使用.
此仓库中包含一个 [GitHub Actions workflow](https://docs.github.com/en/pages/getting-started-with-github-pages/configuring-a-publishing-source-for-your-github-pages-site#publishing-with-a-custom-github-actions-workflow) 来帮助你免费在 GitHub Pages 上自动构建和部署网站.
### 使用
转至[文档](https://imfing.github.io/hextra/zh-cn/docs)
## 贡献
该项目正在积极开发中. 欢迎贡献!
## 许可证
[MIT License](./LICENSE)

File diff suppressed because it is too large Load Diff

View File

@ -4,6 +4,14 @@ nav {
}
}
@supports (
(-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))
) {
.nav-container-blur {
@apply backdrop-blur-md bg-white/[.85] dark:!bg-dark/80;
}
}
.hamburger-menu svg {
g {
@apply origin-center;

View File

@ -0,0 +1,21 @@
.hextra-scrollbar {
scrollbar-width: thin; /* Firefox */
scrollbar-color: oklch(55.55% 0 0 / 40%) transparent; /* Firefox */
scrollbar-gutter: stable;
&::-webkit-scrollbar {
@apply w-3 h-3;
}
&::-webkit-scrollbar-track {
@apply bg-transparent;
}
&::-webkit-scrollbar-thumb {
@apply rounded-[10px];
}
&:hover::-webkit-scrollbar-thumb {
border: 3px solid transparent;
background-color: var(--tw-shadow-color);
background-clip: content-box;
@apply shadow-neutral-500/20 hover:shadow-neutral-500/40;
}
}

View File

@ -1,3 +1,5 @@
@import "tailwind.css";
@import "typography.css";
@import "highlight.css";
@import "components/cards.css";
@ -5,10 +7,7 @@
@import "components/search.css";
@import "components/sidebar.css";
@import "components/navbar.css";
@tailwind base;
@tailwind components;
@tailwind utilities;
@import "components/scrollbar.css";
html {
@apply text-base antialiased;
@ -22,10 +21,12 @@ body {
:root {
--primary-hue: 212deg;
--primary-saturation: 100%;
--navbar-height: 4rem;
--menu-height: 3.75rem;
}
.dark {
--primary-hue: 204deg;
--primary-saturation: 100%;
}

3
assets/css/tailwind.css Normal file
View File

@ -0,0 +1,3 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

View File

@ -20,6 +20,9 @@
p {
@apply mt-6 leading-7 first:mt-0;
}
.not-prose p {
@apply mt-0 leading-normal;
}
a {
@apply text-primary-600 underline decoration-from-font [text-underline-position:from-font];
}

22
assets/js/back-to-top.js Normal file
View File

@ -0,0 +1,22 @@
// Back to top button
document.addEventListener("DOMContentLoaded", function () {
const backToTop = document.querySelector("#backToTop");
if (backToTop) {
document.addEventListener("scroll", (e) => {
if (window.scrollY > 300) {
backToTop.classList.remove("opacity-0");
} else {
backToTop.classList.add("opacity-0");
}
});
}
});
function scrollUp() {
window.scroll({
top: 0,
left: 0,
behavior: "smooth",
});
}

View File

@ -1,30 +1,63 @@
document.querySelectorAll('.code-copy-btn').forEach(function (button) {
button.addEventListener('click', function (e) {
e.preventDefault();
const targetId = button.getAttribute('data-clipboard-target');
const target = document.querySelector(targetId);
let codeElement;
if (target.tagName === 'CODE') {
codeElement = target;
} else {
// Select the last code element in case line numbers are present
const codeElements = target.querySelectorAll('code');
codeElement = codeElements[codeElements.length - 1];
}
if (codeElement) {
// Replace double newlines with single newlines in the innerText
// as each line inside <span> has trailing newline '\n'
const code = codeElement.innerText.replace(/\n\n/g, '\n');
navigator.clipboard.writeText(code).then(function () {
button.classList.add('copied');
setTimeout(function () {
button.classList.remove('copied');
}, 500);
}).catch(function (err) {
console.error('Failed to copy text: ', err);
});
} else {
console.error('Target element not found');
}
// Copy button for code blocks
document.addEventListener('DOMContentLoaded', function () {
const getCopyIcon = () => {
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
svg.innerHTML = `
<path stroke-linecap="round" stroke-linejoin="round" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" />
`;
svg.setAttribute('fill', 'none');
svg.setAttribute('viewBox', '0 0 24 24');
svg.setAttribute('stroke', 'currentColor');
svg.setAttribute('stroke-width', '2');
return svg;
}
const getSuccessIcon = () => {
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
svg.innerHTML = `
<path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7" />
`;
svg.setAttribute('fill', 'none');
svg.setAttribute('viewBox', '0 0 24 24');
svg.setAttribute('stroke', 'currentColor');
svg.setAttribute('stroke-width', '2');
return svg;
}
document.querySelectorAll('.code-copy-btn').forEach(function (button) {
// Add copy and success icons
button.querySelector('.copy-icon')?.appendChild(getCopyIcon());
button.querySelector('.success-icon')?.appendChild(getSuccessIcon());
// Add click event listener for copy button
button.addEventListener('click', function (e) {
e.preventDefault();
const targetId = button.getAttribute('data-clipboard-target');
const target = document.querySelector(targetId);
let codeElement;
if (target.tagName === 'CODE') {
codeElement = target;
} else {
// Select the last code element in case line numbers are present
const codeElements = target.querySelectorAll('code');
codeElement = codeElements[codeElements.length - 1];
}
if (codeElement) {
// Replace double newlines with single newlines in the innerText
// as each line inside <span> has trailing newline '\n'
const code = codeElement.innerText.replace(/\n\n/g, '\n');
navigator.clipboard.writeText(code).then(function () {
button.classList.add('copied');
setTimeout(function () {
button.classList.remove('copied');
}, 500);
}).catch(function (err) {
console.error('Failed to copy text: ', err);
});
} else {
console.error('Target element not found');
}
});
});
});

View File

@ -1,5 +1,16 @@
// Search functionality using FlexSearch.
// Change shortcut key to cmd+k on Mac, iPad or iPhone.
document.addEventListener("DOMContentLoaded", function () {
if (/iPad|iPhone|Macintosh/.test(navigator.userAgent)) {
// select the kbd element under the .search-wrapper class
const keys = document.querySelectorAll(".search-wrapper kbd");
keys.forEach(key => {
key.innerHTML = '<span class="text-xs">⌘</span>K';
});
}
});
// Render the search data as JSON.
// {{ $searchDataFile := printf "%s.search-data.json" .Language.Lang }}
// {{ $searchData := resources.Get "json/search-data.json" | resources.ExecuteAsTemplate $searchDataFile . }}

View File

@ -1,36 +1,51 @@
// Dark theme toggle
// Light / Dark theme toggle
(function () {
const defaultTheme = '{{ site.Params.theme.default | default `system`}}'
const themeToggleButtons = document.querySelectorAll(".theme-toggle");
const themeToggleButtons = document.querySelectorAll(".theme-toggle");
// Change the icons inside the button based on previous settings
if (
localStorage.getItem("color-theme") === "dark" ||
(!("color-theme" in localStorage) && window.matchMedia("(prefers-color-scheme: dark)").matches)
) {
themeToggleButtons.forEach((el) => el.dataset.theme = "dark");
} else {
themeToggleButtons.forEach((el) => el.dataset.theme = "light");
}
// Change the icons of the buttons based on previous settings or system theme
if (
localStorage.getItem("color-theme") === "dark" ||
(!("color-theme" in localStorage) &&
((window.matchMedia("(prefers-color-scheme: dark)").matches && defaultTheme === "system") || defaultTheme === "dark"))
) {
themeToggleButtons.forEach((el) => el.dataset.theme = "dark");
} else {
themeToggleButtons.forEach((el) => el.dataset.theme = "light");
}
themeToggleButtons.forEach((el) => {
el.addEventListener("click", function () {
if (localStorage.getItem("color-theme")) {
if (localStorage.getItem("color-theme") === "light") {
document.documentElement.classList.add("dark");
localStorage.setItem("color-theme", "dark");
// Add click event handler to the buttons
themeToggleButtons.forEach((el) => {
el.addEventListener("click", function () {
if (localStorage.getItem("color-theme")) {
if (localStorage.getItem("color-theme") === "light") {
setDarkTheme();
localStorage.setItem("color-theme", "dark");
} else {
setLightTheme();
localStorage.setItem("color-theme", "light");
}
} else {
document.documentElement.classList.remove("dark");
localStorage.setItem("color-theme", "light");
if (document.documentElement.classList.contains("dark")) {
setLightTheme();
localStorage.setItem("color-theme", "light");
} else {
setDarkTheme();
localStorage.setItem("color-theme", "dark");
}
}
} else {
if (document.documentElement.classList.contains("dark")) {
document.documentElement.classList.remove("dark");
localStorage.setItem("color-theme", "light");
} else {
document.documentElement.classList.add("dark");
localStorage.setItem("color-theme", "dark");
}
}
el.dataset.theme = document.documentElement.classList.contains("dark") ? "dark" : "light";
el.dataset.theme = document.documentElement.classList.contains("dark") ? "dark" : "light";
});
});
});
// Listen for system theme changes
window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", (e) => {
if (defaultTheme === "system" && !("color-theme" in localStorage)) {
e.matches ? setDarkTheme() : setLightTheme();
themeToggleButtons.forEach((el) =>
el.dataset.theme = document.documentElement.classList.contains("dark") ? "dark" : "light"
);
}
});
})();

View File

@ -1,3 +1,10 @@
{{/* FlexSearch Index Data */}}
{{- $indexType := site.Params.search.flexsearch.index | default "content" -}}
{{- if not (in (slice "content" "summary" "heading" "title" ) $indexType) -}}
{{- errorf "unknown flexsearch index type: %s" $indexType -}}
{{- end -}}
{{- $pages := where .Site.Pages "Kind" "in" (slice "page" "section") -}}
{{- $pages = where $pages "Params.excludeSearch" "!=" true -}}
{{- $pages = where $pages "Content" "!=" "" -}}
@ -7,7 +14,7 @@
{{- range $index, $page := $pages -}}
{{- $pageTitle := $page.LinkTitle | default $page.File.BaseFileName -}}
{{- $pageLink := $page.RelPermalink -}}
{{- $data := partial "utils/fragments" $page -}}
{{- $data := partial "utils/fragments" (dict "context" $page "type" $indexType) -}}
{{- $output = $output | merge (dict $pageLink (dict "title" $pageTitle "data" $data)) -}}
{{- end -}}

View File

@ -1,30 +0,0 @@
build:
buildStats:
enable: true
disableIDs: true
cacheBusters:
- source: assets/watching/hugo_stats\.json
target: styles\.css
- source: assets/.*\.(js|ts|jsx|tsx)
target: (js|scripts|javascript)
- source: assets/.*\.(css|sass|scss)$
target: (css|styles|scss|sass)
- source: (postcss|tailwind)\.config\.js
target: (css|styles|scss|sass)
- source: assets/.*\.(.*)$
target: $1
module:
mounts:
- source: static
target: static
- source: layouts
target: layouts
- source: data
target: data
- source: assets
target: assets
- source: i18n
target: i18n
- source: archetypes
target: archetypes

26
dev.toml Normal file
View File

@ -0,0 +1,26 @@
# Theme development config for exampleSite
# https://gohugo.io/getting-started/configuration/#configure-cache-busters
[build]
[build.buildStats]
enable = true
disableIDs = true
[[build.cachebusters]]
source = 'assets/watching/hugo_stats\.json'
target = 'styles\.css'
[[build.cachebusters]]
source = '(postcss|tailwind)\.config\.js'
target = 'css'
[[build.cachebusters]]
source = 'assets/.*\.(js|ts|jsx|tsx)'
target = 'js'
[[build.cachebusters]]
source = 'assets/.*\.(.*)$'
target = '$1'
[module]
[[module.mounts]]
source = "assets"
target = "assets"
[[module.mounts]]
source = "hugo_stats.json"
target = "assets/watching/hugo_stats.json"

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 KiB

View File

@ -2,3 +2,75 @@
title: Hextra Theme
layout: hextra-home
---
{{< hextra/hero-badge >}}
<div class="w-2 h-2 rounded-full bg-primary-400"></div>
<span>Free, open source</span>
{{< icon name="arrow-circle-right" attributes="height=14" >}}
{{< /hextra/hero-badge >}}
<div class="mt-6 mb-6">
{{< hextra/hero-headline >}}
Build modern websites&nbsp;<br class="sm:block hidden" />with Markdown and Hugo
{{< /hextra/hero-headline >}}
</div>
<div class="mb-12">
{{< hextra/hero-subtitle >}}
Fast, batteries-included Hugo theme&nbsp;<br class="sm:block hidden" />for creating beautiful static websites
{{< /hextra/hero-subtitle >}}
</div>
<div class="mb-6">
{{< hextra/hero-button text="Get Started" link="docs" >}}
</div>
<div class="mt-6"></div>
{{< hextra/feature-grid >}}
{{< hextra/feature-card
title="Fast and Full-featured"
subtitle="Simple and easy to use, yet powerful and feature-rich."
class="aspect-auto md:aspect-[1.1/1] max-md:min-h-[340px]"
image="images/hextra-doc.webp"
imageClass="top-[40%] left-[24px] w-[180%] sm:w-[110%] dark:opacity-80"
style="background: radial-gradient(ellipse at 50% 80%,rgba(194,97,254,0.15),hsla(0,0%,100%,0));"
>}}
{{< hextra/feature-card
title="Markdown is All You Need"
subtitle="Compose with just Markdown. Enrich with Shortcode components."
class="aspect-auto md:aspect-[1.1/1] max-lg:min-h-[340px]"
image="images/hextra-markdown.webp"
imageClass="top-[40%] left-[36px] w-[180%] sm:w-[110%] dark:opacity-80"
style="background: radial-gradient(ellipse at 50% 80%,rgba(142,53,74,0.15),hsla(0,0%,100%,0));"
>}}
{{< hextra/feature-card
title="Full Text Search"
subtitle="Built-in full text search with FlexSearch, no extra setup required."
class="aspect-auto md:aspect-[1.1/1] max-md:min-h-[340px]"
image="images/hextra-search.webp"
imageClass="top-[40%] left-[36px] w-[110%] sm:w-[110%] dark:opacity-80"
style="background: radial-gradient(ellipse at 50% 80%,rgba(221,210,59,0.15),hsla(0,0%,100%,0));"
>}}
{{< hextra/feature-card
title="Lightweight as a Feather"
subtitle="No dependency or Node.js is needed to use Hextra. Powered by Hugo, one of *the fastest* static site generators, building your site in just seconds with a single binary."
>}}
{{< hextra/feature-card
title="Reponsive with Dark Mode Included"
subtitle="Looks great on different screen sizes. Built-in dark mode support, with auto-switching based on user's system preference."
>}}
{{< hextra/feature-card
title="Build and Host for Free"
subtitle="Build with GitHub Actions, and host for free on GitHub Pages. Alternatively it can be hosted on any static hosting service."
>}}
{{< hextra/feature-card
title="Multi-Language Made Easy"
subtitle="Create multi-language pages by just adding locales suffix to the Markdown file. Adding i18n support to your site is intuitive."
>}}
{{< hextra/feature-card
title="And Much More..."
icon="sparkles"
subtitle="Syntax highlighting / Table of contents / SEO / RSS / LaTeX / Mermaid / Customizable / and more..."
>}}
{{< /hextra/feature-grid >}}

View File

@ -0,0 +1,20 @@
---
title: 关于
toc: false
---
Hextra 是一款简洁、快速、灵活的主题适用于构建现代化静态站点。Hextra 特别适用于文档网站,但也可用于构建博客、个人网站等各种类型的网站。
Hugo 和 Jekyll 类似是一个静态网站生成器。但与其他生成器不同Hugo 只有单个可执行文件这使得它可以轻松地在各种平台上安装和运行。Hugo 的运行速度非常快且可靠性高,能够在几毫秒内渲染数千页的网站。
Hextra 被设计为轻量级,具有最小化的内存占用。使用 Hextra 无需安装繁杂的依赖,比如 Node.js相反你只需要一个简单的 YAML 配置文件和 Markdown 内容。因此,我们可以专注于内容而非在配置环境上浪费精力。
## 鸣谢
Hextra 的设计离不开这些项目的支持和其提供的灵感:
- [Hugo](https://gohugo.io/)
- [Tailwind CSS](https://tailwindcss.com/)
- [Heroicons](https://heroicons.com/)
- [Nextra](https://nextra.vercel.app/)
- [Next.js](https://nextjs.org/)

View File

@ -0,0 +1,3 @@
---
title: "博客"
---

View File

@ -0,0 +1,137 @@
---
title: Markdown 语法指南
date: 2020-01-01
authors:
- name: John Doe
link: https://example.com/johndoe
excludeSearch: true
---
这篇文章提供了一些基础的 Markdown 语法样例,这些可以在 Hugo 的内容文件中使用。
<!--more-->
## 基础语法
### 标题
```
# 一级标题
## 二级标题
### 三级标题
#### 四级标题
##### 五级标题
###### 六级标题
```
## 二级标题
### 三级标题
#### 四级标题
##### 五级标题
###### 六级标题
```text
*这段文字将是斜体*
_这也将是斜体_
**这段文字将是粗体**
__这也将是粗体__
_你 **可以** 组合它们_
```
*这段文字将是斜体*
_这也将是斜体_
**这段文字将是粗体**
__这也将是粗体__
_你 **可以** 组合它们_
### 列表
#### 无序列表
* 项目 1
* 项目 2
* 项目 2a
* 项目 2b
#### 有序列表
1. 项目 1
2. 项目 2
3. 项目 3
1. 项目 3a
2. 项目 3b
### 图片
```markdown
![GitHub Logo](https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png)
```
![GitHub Logo](https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png)
### 链接
```markdown
[Hugo](https://gohugo.io)
```
[Hugo](https://gohugo.io)
### 块引用
```markdown
牛顿曾说:
> 如果我看得更远,那是因为我站在巨人的肩膀上。
```
> 如果我看得更远,那是因为我站在巨人的肩膀上。
### 行内代码
```markdown
行内 `代码``反引号` 包围。
```
行内 `代码``反引号` 包围。
### 代码块
#### 语法高亮
````markdown
```go
func main() {
fmt.Println("Hello World")
}
```
````
```go
func main() {
fmt.Println("Hello World")
}
```
### 表格
```markdown
| Syntax | Description |
| --------- | ----------- |
| Header | Title |
| Paragraph | Text |
```
| Syntax | Description |
| --------- | ----------- |
| Header | Title |
| Paragraph | Text |
## 参考
- [Markdown Syntax](https://www.markdownguide.org/basic-syntax/)
- [Hugo Markdown](https://gohugo.io/content-management/formats/#markdown)

View File

@ -0,0 +1,40 @@
---
linkTitle: "文档"
title: 介绍
---
👋 你好!欢迎来到 Hextra 文档!
<!--more-->
## Hextra 是什么?
Hextra 是一款现代、快速且内置丰富功能的 [Hugo][hugo] 主题,它是用 [Tailwind CSS][tailwind-css] 构建的。该主题旨在创建美观的文档、博客和网站,提供了开箱即用的功能和灵活性以满足各种需求。
## 功能特点
- **优美的设计** - 受到 Nextra 的启发Hextra 利用 Tailwind CSS 提供了一种现代设计,使您的网站看起来出色。
- **响应式布局和深色模式** - 无论是在移动设备、平板还是桌面上,都表现出色。同时支持深色模式以适应各种光线条件。
- **快速和轻量级** - 由 Hugo 驱动一个轻量级且超快的静态网站生成器封装在一个单一的二进制文件中Hextra 保持其占用极小。使用它不需要 Javascript 或 Node.js。
- **全文搜索** - 内置的离线全文搜索由 FlexSearch 提供支持,无需额外配置。
- **功能全面** - 支持 Markdown、语法高亮、LaTeX 数学公式、图表以及 Shortcodes 元素以增强您的内容。目录、面包屑、分页、侧边栏导航等都会自动生成。
- **多语言和 SEO 支持** - Hugo 的多语言模式轻松支持多语言网站。对于 SEO 标签、Open Graph 和 Twitter 卡片,也提供了开箱即用的支持。
## 有问题或反馈?
{{< callout emoji="❓" >}}
Hextra 仍在积极开发中。
有问题或反馈?请随时[提出问题](https://github.com/imfing/hextra/issues)
{{< /callout >}}
## 接下来
直接进入以下部分开始:
{{< cards >}}
{{< card link="getting-started" title="入门指南" icon="document-text" subtitle="学习如何使用 Hextra 创建网站" >}}
{{< /cards >}}
[hugo]: https://gohugo.io/
[flex-search]: https://github.com/nextapps-de/flexsearch
[tailwind-css]: https://tailwindcss.com/

View File

@ -1,6 +1,8 @@
---
linkTitle: Advanced
title: Advanced Topics
prev: /docs/guide/shortcodes/tabs
next: /docs/advanced/multi-language
---
This section covers some advanced topics of the theme.
@ -10,4 +12,5 @@ This section covers some advanced topics of the theme.
{{< cards >}}
{{< card link="multi-language" title="Multi-language" icon="translate" >}}
{{< card link="customization" title="Customization" icon="pencil" >}}
{{< card link="comments" title="Comments System" icon="chat-alt" >}}
{{< /cards >}}

View File

@ -0,0 +1,15 @@
---
linkTitle: 高级配置
title: 高级配置
prev: /docs/guide/shortcodes/tabs
next: /docs/advanced/multi-language
---
此部分提供了 Hextra 的一些高级配置。
<!--more-->
{{< cards >}}
{{< card link="multi-language" title="多语言" icon="translate" >}}
{{< card link="customization" title="定制化" icon="pencil" >}}
{{< /cards >}}

View File

@ -0,0 +1,39 @@
---
title: Comments System
linkTitle: Comments
---
Hextra supports adding comments system to your site.
Currently [giscus](https://giscus.app/) is supported.
<!--more-->
## giscus
[giscus](https://giscus.app/) is a comments system powered by [GitHub Discussions](https://docs.github.com/en/discussions). It is free and open source.
To enable giscus, you need to add the following to the site configuration file:
```yaml {filename="hugo.yaml"}
params:
comments:
enable: false
type: giscus
giscus:
repo: <repository>
repoId: <repository ID>
category: <category>
categoryId: <category ID>
```
The giscus configurations can be constructed from the [giscus.app](https://giscus.app/) website. More details can also be found there.
Comments can be enabled or disabled for a specific page in the page front matter:
```yaml {filename="content/docs/about.md"}
---
title: About
comments: true
---
```

View File

@ -10,7 +10,11 @@ This page describes the available options and how to customize the theme further
## Custom CSS
To add custom CSS, we need to create a file `assets/css/custom.css` in our site. Hextra will automatically load this file. For example, customize the font family of the content:
To add custom CSS, we need to create a file `assets/css/custom.css` in our site. Hextra will automatically load this file.
### Font Family
The font family of the content can be customized using:
```css {filename="assets/css/custom.css"}
.content {
@ -18,13 +22,24 @@ To add custom CSS, we need to create a file `assets/css/custom.css` in our site.
}
```
### Inline Code Element
The color of text mixed with `other text` can customized with:
```css {filename="assets/css/custom.css"}
.content code:not(.code-block code) {
color: #c97c2e;
}
```
### Primary Color
The primary color of the theme can be customized by setting the `--primary-hue` variable:
The primary color of the theme can be customized by setting the `--primary-hue` and `--primary-saturation` variables:
```css {filename="assets/css/custom.css"}
:root {
--primary-hue: 100deg;
--primary-saturation: 90%;
}
```

View File

@ -0,0 +1,58 @@
---
title: 自定义 Hextra
linkTitle: 自定义
---
Hextra 在 `hugo.yaml` 中提供了一些自定义选项来配置主题。
本页介绍了可用选项以及如何进一步自定义主题。
<!--more-->
## 自定义 CSS
要添加自定义 CSS我们需要在站点中创建一个文件 `assets/css/custom.css`。Hextra 将自动加载该文件,比如自定义字体:
```css {filename="assets/css/custom.css"}
.content {
font-family: "Times New Roman", Times, serif;
}
```
### 主题色
主题色可以通过设置 `--primary-hue` 变量来自定义:
```css {filename="assets/css/custom.css"}
:root {
--primary-hue: 100deg;
}
```
### 代码高亮
代码高亮风格的详细信息可在 [Chroma Styles Gallery](https://xyproto.github.io/splash/docs/all.html) 中找到。 可以使用以下命令生成样式表:
```bash
$ hugo gen chromastyles --style=github
```
可将生成的样式添加到自定义 CSS 文件中以覆盖默认代码高亮样式。
## 自定义 Script
你可以添加以下文件以自定义 `script` 添加到每页的 `head` 最后:
```
layouts/partials/custom/head-end.html
```
## 自定义布局
可以在站点的 `layouts` 目录中创建同名文件来覆盖主题的默认布局。
例如,要覆盖文档的 `single.html` 布局,在站点中创建文件 `layouts/docs/single.html`。
如需或许更多信息,转至 [Hugo Templates](https://gohugo.io/templates/)。
## 进一步定制 Hextra
没有找到你想修改的东西?在 GitHub 上[创建 Issues](https://github.com/imfing/hextra/issues) 或为 Hextra 贡献你的智慧!

View File

@ -1,6 +1,7 @@
---
title: "Multi-language"
weight: 1
prev: /docs/advanced
---
Hextra supports creating site with multiple languages using Hugo's [multilingual mode](https://gohugo.io/content-management/multilingual/).

View File

@ -0,0 +1,74 @@
---
title: "多语言"
weight: 1
prev: /docs/advanced
---
Hextra 支持使用 Hugo 的[多语言模式](https://gohugo.io/content-management/multilingual/) 创建多语言的网站。
<!--more-->
## 启用多语言支持
为了使我们的网站支持多语言,我们需要告诉 Hugo 需要支持的语言。 在站点配置文件中添加:
```yaml {filename="hugo.yaml"}
defaultContentLanguage: en
languages:
en:
languageName: English
weight: 1
fr:
languageName: Français
weight: 2
ja:
languageName: 日本語
weight: 3
```
## 按文件名管理翻译
Hugo 支持按文件名管理翻译。例如,如果我们有一个英文文件 `content/docs/_index.md`,我们可以创建一个翻译为法语的文件 `content/docs/_index.fr.md`。
{{< filetree/container >}}
{{< filetree/folder name="content" >}}
{{< filetree/folder name="docs" state="open" >}}
{{< filetree/file name="_index.md" >}}
{{< filetree/file name="_index.fr.md" >}}
{{< filetree/file name="_index.ja.md" >}}
{{< /filetree/folder >}}
{{< /filetree/folder >}}
{{< /filetree/container >}}
注意Hugo 还支持[按内容目录管理翻译](https://gohugo.io/content-management/multilingual/#translation-by-content-directory)。
## 翻译菜单项
要翻译导航栏中的菜单项,我们需要设置 `identifier` 字段:
```yaml {filename="hugo.yaml"}
menu:
main:
- identifier: documentation
name: Documentation
pageRef: /docs
weight: 1
- identifier: blog
name: Blog
pageRef: /blog
weight: 2
```
## 翻译字符串
要翻译其他地方的字符串,我们需要将翻译添加到相应的 `i18n` 文件中:
```yaml {filename="i18n/fr.yaml"}
readMore: Lire la suite
```
## 更多参考
- [Hugo Multilingual Mode](https://gohugo.io/content-management/multilingual/)
- [Hugo Multilingual Part 1: Content translation](https://www.regisphilibert.com/blog/2018/08/hugo-multilingual-part-1-managing-content-translation/)
- [Hugo Multilingual Part 2: Strings localization](https://www.regisphilibert.com/blog/2018/08/hugo-multilingual-part-2-i18n-string-localization/)

View File

@ -7,7 +7,7 @@ prev: /docs
## Quick Start from Template
{{< icon "github" >}} [imfing/hextra-starter-template](https://github.com/imfing/hextra-starter-template)
{{< icon "github" >}}&nbsp;[imfing/hextra-starter-template](https://github.com/imfing/hextra-starter-template)
You will be able to quickly get started by using the above template repository.
@ -19,18 +19,29 @@ We have provided a [GitHub Actions workflow](https://docs.github.com/en/pages/ge
## Start as New Project
### Prerequisites
There are two main ways to add the Hextra theme to your Hugo project.
Before we start, make sure we have [Hugo](https://gohugo.io/) installed.
Please refer to Hugo's [official installation guide](https://gohugo.io/installation/) for more details.
1. **Hugo Modules (Recommended)**: The simplest and recommended method. [Hugo modules](https://gohugo.io/hugo-modules/) let you pull in the theme directly from its online source. Theme is downloaded automatically and managed by Hugo.
[Hugo modules](https://gohugo.io/hugo-modules/) are the recommended way to manage Hugo themes. To use Hugo modules, we need to install [Git](https://git-scm.com/) and [Go](https://go.dev/).
2. **Git Submodule**: Alternatively, add Hextra as a [Git Submodule](https://git-scm.com/book/en/v2/Git-Tools-Submodules). The theme will be downloaded by Git and stored in your project's `themes` folder.
### Setup Hextra as Hugo module
#### Prerequisites
Before starting, you need to have the following softwares installed:
- [Hugo (extended version)](https://gohugo.io/installation/)
- [Git](https://git-scm.com/)
- [Go](https://go.dev/)
#### Steps
{{% steps %}}
### Initialize a new Hugo site
```bash
```shell
$ hugo new site my-site --format=yaml
```
@ -45,7 +56,7 @@ $ hugo mod init github.com/username/my-site
$ hugo mod get github.com/imfing/hextra
```
Edit `hugo.yaml` to enable Hextra theme:
Configure `hugo.yaml` to use Hextra theme by adding the following:
```yaml
module:
@ -55,7 +66,7 @@ module:
### Create your first content pages
Let's create a new content page for the home page and the documentation page:
Let's create new content page for the home page and the documentation page:
```shell
$ hugo new content/_index.md
@ -65,7 +76,7 @@ $ hugo new content/docs/_index.md
### Preview the site locally
```shell
$ hugo server
$ hugo server --buildDrafts --disableFastRender
```
Voila! You can see your new site at `http://localhost:1313/`.
@ -73,6 +84,102 @@ Voila! You can see your new site at `http://localhost:1313/`.
{{% /steps %}}
{{% details title="How to update theme?" %}}
To update all Hugo modules in your project to their latest versions, run the following command:
```shell
$ hugo mod get -u
```
To update only Hextra to the [latest released version](https://github.com/imfing/hextra/releases), run the following command:
```shell
hugo mod get -u github.com/imfing/hextra
```
See [Hugo Modules](https://gohugo.io/hugo-modules/use-modules/#update-all-modules) for more details.
{{% /details %}}
### Setup Hextra as Git submodule
#### Prerequisites
Before starting, you need to have the following softwares installed:
- [Hugo (extended version)](https://gohugo.io/installation/)
- [Git](https://git-scm.com/)
#### Steps
{{% steps %}}
### Initialize a new Hugo site
```shell
$ hugo new site my-site --format=yaml
```
### Add Hextra theme as a Git submodule
```shell
git submodule add https://github.com/imfing/hextra.git themes/hextra
```
Configure `hugo.yaml` to use Hextra theme by adding the following:
```yaml
theme: hextra
```
### Create your first content pages
Let's create new content page for the home page and the documentation page:
```shell
$ hugo new content/_index.md
$ hugo new content/docs/_index.md
```
### Preview the site locally
```shell
$ hugo server --buildDrafts --disableFastRender
```
Voila! You can see your new site at `http://localhost:1313/`.
{{% /steps %}}
When using [CI/CD](https://en.wikipedia.org/wiki/CI/CD) for Hugo website deployment, it's essential to ensure that the following command is executed before running the `hugo` command.
```shell
git submodule update --init
```
Failure to run this command will result in the theme folder not being populated with Hextra theme files, leading to a build failure.
{{% details title="How to update theme?" %}}
To update all submodules in your repository to their latest commits, run the following command:
```shell
$ git submodule update --remote
```
To update only Hextra to the latest commit, run the following command:
```shell
git submodule update --remote themes/hextra
```
See [Git submodules](https://git-scm.com/book/en/v2/Git-Tools-Submodules) for more details.
{{% /details %}}
## Next
Explore the following sections to start adding more contents:

View File

@ -0,0 +1,83 @@
---
title: 快速开始
weight: 1
next: /docs/guide
prev: /docs
---
## 使用模板快速开始
{{< icon "github" >}}&nbsp;[imfing/hextra-starter-template](https://github.com/imfing/hextra-starter-template)
通过使用上面的模板仓库,您将能够快速地开始。
<img src="https://docs.github.com/assets/cb-77734/mw-1440/images/help/repository/use-this-template-button.webp" width="500">
我们提供了一个 [GitHub Actions 工作流](https://docs.github.com/cn/pages/getting-started-with-github-pages/configuring-a-publishing-source-for-your-github-pages-site#publishing-with-a-custom-github-actions-workflow),它可以帮助您自动构建并部署您的网站到 GitHub Pages并免费托管。
[🌐 演示 ↗](https://imfing.github.io/hextra-starter-template/)
## 作为新项目开始
### 前提条件
在开始之前,请确保我们已经安装了 [Hugo](https://gohugo.io/)。
请参考 Hugo 的[官方安装指南](https://gohugo.io/installation/)以获取更多详情。
[Hugo 模块](https://gohugo.io/hugo-modules/)是管理 Hugo 主题的推荐方式。要使用 Hugo 模块,我们需要安装 [Git](https://git-scm.com/) 和 [Go](https://go.dev/)。
{{% steps %}}
### 初始化 Hugo 站点
```bash
$ hugo new site my-site --format=yaml
```
### 通过模块配置 Hextra 主题
```shell
# 初始化 Hugo 模块
$ cd my-site
$ hugo mod init github.com/username/my-site
# 添加 Hextra
$ hugo mod get github.com/imfing/hextra
```
编辑 `hugo.yaml` 以启用 Hextra
```yaml
module:
imports:
- path: github.com/imfing/hextra
```
### 创建你的第一个内容页
让我们为主页和文档页面创建一个新的内容页面:
```shell
$ hugo new content/_index.md
$ hugo new content/docs/_index.md
```
### 在本地预览站点
```shell
$ hugo server --buildDrafts --disableFastRender
```
瞧!你现在可以在 `http://localhost:1313/` 看到你的新站点。
{{% /steps %}}
## 接下来
你可以探索以下部分来添加更多内容:
{{< cards >}}
{{< card link="../guide/organize-files" title="目录结构" icon="document-duplicate" >}}
{{< card link="../guide/configuration" title="配置文件指南" icon="adjustments" >}}
{{< card link="../guide/markdown" title="Markdown" icon="markdown" >}}
{{< /cards >}}

View File

@ -1,6 +1,7 @@
---
title: Guide
weight: 2
prev: /docs/getting-started
next: /docs/guide/organize-files
sidebar:
open: true

View File

@ -0,0 +1,22 @@
---
title: 指南
weight: 2
prev: /docs/getting-started
next: /docs/guide/organize-files
sidebar:
open: true
---
探索以下各节以学习如何使用 Hextra 编写内容:
<!--more-->
{{< cards >}}
{{< card link="organize-files" title="目录结构" icon="document-duplicate" >}}
{{< card link="configuration" title="配置" icon="adjustments" >}}
{{< card link="markdown" title="Markdown" icon="markdown" >}}
{{< card link="syntax-highlighting" title="代码高亮" icon="sparkles" >}}
{{< card link="latex" title="LaTeX 公式" icon="variable" >}}
{{< card link="diagrams" title="图表" icon="chart-square-bar" >}}
{{< card link="shortcodes" title="短代码" icon="template" >}}
{{< /cards >}}

View File

@ -5,7 +5,7 @@ weight: 2
Hugo reads its configuration from `hugo.yaml` in the root of your Hugo site.
The config file is where you can configure all aspects of your site.
You can find the config file for this site in `exampleSite/hugo.yaml` as a good starting point.
Check out the config file for this site [`exampleSite/hugo.yaml`](https://github.com/imfing/hextra/blob/main/exampleSite/hugo.yaml) on GitHub to get a comprehensive idea of available settings and best practices.
<!--more-->
@ -65,6 +65,24 @@ There are different types of menu items:
These menu items can be sorted by setting the `weight` parameter.
### Logo and Title
To modify the default logo, edit `hugo.yaml` and add the path to your logo file under `static` directory.
Optionally, you can change the link that users are redirected to when clicking on your logo, as well as set the width & height of the logo in pixels.
```yaml {filename="hugo.yaml"}
params:
navbar:
displayTitle: true
displayLogo: true
logo:
path: images/logo.svg
dark: images/logo-dark.svg
link: /
width: 40
height: 20
```
## Sidebar
### Main Sidebar
@ -124,3 +142,118 @@ params:
editURL: "https://example.com/edit/this/page"
---
```
## Footer
### Copyright
To modify the copyright text displayed in your website's footer, you'll need to create a file named `i18n/en.yaml`.
In this file, specify your new copyright text as shown below:
```yaml {filename="i18n/en.yaml"}
copyright: "© 2023 YOUR TEXT HERE"
```
For your reference, an example [`i18n/en.yaml`](https://github.com/imfing/hextra/blob/main/i18n/en.yaml) file can be found in the GitHub repository. Additionally, you could use Markdown format in the copyright text.
## Others
### Favicon
To customize the [favicon](https://en.wikipedia.org/wiki/Favicon) for your site, place icon files under the `static` folder to override the [default favicons from the theme](https://github.com/imfing/hextra/tree/main/static):
{{< filetree/container >}}
{{< filetree/folder name="static" >}}
{{< filetree/file name="android-chrome-192x192.png" >}}
{{< filetree/file name="android-chrome-512x512.png" >}}
{{< filetree/file name="apple-touch-icon.png" >}}
{{< filetree/file name="favicon-16x16.png" >}}
{{< filetree/file name="favicon-32x32.png" >}}
{{< filetree/file name="favicon-dark.svg" >}}
{{< filetree/file name="favicon.ico" >}}
{{< filetree/file name="favicon.svg" >}}
{{< filetree/file name="site.webmanifest" >}}
{{< /filetree/folder >}}
{{< /filetree/container >}}
Include both `favicon.ico` and `favicon.svg` files in your project to ensure your site's favicons display correctly.
While `favicon.ico` is generally for older browsers, `favicon.svg` is supported by modern ones. The optional `favicon-dark.svg` can be included for a tailored experience in dark mode.
Feel free to use tools like [favicon.io](https://favicon.io/) or [favycon](https://github.com/ruisaraiva19/favycon) to generate these icons.
### Theme Configuration
Use the `theme` setting to configure the default theme mode and toggle button, allowing visitors to switch between light or dark mode.
```yaml {filename="hugo.yaml"}
params:
theme:
# light | dark | system
default: system
displayToggle: true
```
Options for `theme.default`:
- `light` - always use light mode
- `dark` - always use dark mode
- `system` - sync with the operating system setting (default)
The `theme.displayToggle` parameter allows you to display a toggle button for changing themes.
When set to `true`, visitors can switch between light or dark mode, overriding the default setting.
### Page Width
The width of the page can be customized by the `params.page.width` parameter in the config file:
```yaml {filename="hugo.yaml"}
params:
page:
# full (100%), wide (90rem), normal (1280px)
width: wide
```
There are three available options: `full`, `wide`, and `normal`. By default, the page width is set to `normal`.
Similarly, the width of the navbar and footer can be customized by the `params.navbar.width` and `params.footer.width` parameters.
### Search Index
Full-text search powered by [FlexSearch](https://github.com/nextapps-de/flexsearch) is enabled by default.
To customize the search index, set the `params.search.flexsearch.index` parameter in the config file:
```yaml {filename="hugo.yaml"}
params:
# Search
search:
enable: true
type: flexsearch
flexsearch:
# index page by: content | summary | heading | title
index: content
```
Options for `flexsearch.index`:
- `content` - full content of the page (default)
- `summary` - summary of the page, see [Hugo Content Summaries](https://gohugo.io/content-management/summaries/) for more details
- `heading` - level 1 and level 2 headings
- `title` - only include the page title
To exclude a page from the search index, set the `excludeSearch: true` in the front matter of the page:
```yaml {filename="content/docs/guide/configuration.md"}
---
title: Configuration
excludeSearch: true
---
```
### Google Analytics
To enable Google Analytics, set the `googleAnalytics` parameter in the config file:
```yaml {filename="hugo.yaml"}
googleAnalytics: G-XXXXXXXXXX
```

View File

@ -0,0 +1,125 @@
---
title: 配置文件
weight: 2
---
Hugo 从 Hugo 网站根目录下的 `hugo.yaml` 读取配置。
在配置文件中,您可以配置站点的所有选项。
你可以在 `exampleSite/hugo.yaml` 中找到此站点的配置文件作为开始。
<!--more-->
## 导航栏
### 菜单
右上角的菜单在配置文件的 `menu.main` 中配置:
```yaml {filename="hugo.yaml"}
menu:
main:
- name: Documentation
pageRef: /docs
weight: 1
- name: Blog
pageRef: /blog
weight: 2
- name: About
pageRef: /about
weight: 3
- name: Search
weight: 4
params:
type: search
- name: GitHub
weight: 5
url: "https://github.com/imfing/hextra"
params:
icon: github
```
有几种不同类型的菜单项:
1. Link to a page in the site with `pageRef`
```yaml
- name: Documentation
pageRef: /docs
```
2. Link to an external URL with `url`
```yaml
- name: GitHub
url: "https://github.com"
```
3. Search bar with `type: search`
```yaml
- name: Search
params:
type: search
```
4. Icon
```yaml
- name: GitHub
params:
icon: github
```
这些菜单项可以通过设置 `weight` 进行排序。
## 侧边栏
### 主侧边栏
主侧边栏是自动从 `content` 目录结构生成的。
有关更多详细信息,转至 [目录结构](/docs/guide/organize-files)。
### 额外链接
侧边栏的额外链接在配置文件的 `menu.sidebar` 部分中配置:
```yaml {filename="hugo.yaml"}
menu:
sidebar:
- name: More
params:
type: separator
weight: 1
- name: "About"
pageRef: "/about"
weight: 2
- name: "Hugo Docs ↗"
url: "https://gohugo.io/documentation/"
weight: 3
```
## 右侧边栏
### 目录
目录是根据内容文件中的标题自动生成的,可以在 `front matter` 设置 `tocfalse` 来禁用它。
```yaml {filename="content/docs/guide/configuration.md"}
---
title: Configuration
toc: false
---
```
### 编辑此页链接
要配置编辑此页链接,我们可以在配置文件中设置 `params.editURL.base`
```yaml {filename="hugo.yaml"}
params:
editURL:
base: "https://github.com/your-username/your-repo/edit/main"
```
将为每个页面自动生成编辑链接。
如需为特定页面设置编辑链接,可以在页面的 `front matter` 中设置 `params.editURL`
```yaml {filename="content/docs/guide/configuration.md"}
---
title: Configuration
params:
editURL: "https://example.com/edit/this/page"
---
```

View File

@ -1,6 +1,7 @@
---
title: Diagrams
weight: 6
next: /docs/guide/shortcodes
---
Currently, Hextra supports [Mermaid](#mermaid) for diagrams.

View File

@ -0,0 +1,53 @@
---
title: 图表
weight: 6
next: /docs/guide/shortcodes
---
目前Hextra 支持 [Mermain](#mermaid) 的图表。
<!--more-->
## Mermaid
[Mermaid](https://github.com/mermaid-js/mermaid#readme) 是一个基于 JavaScript 的图表绘制工具,它的文本定义和 Markdown 类似,可在浏览器中动态创建图表。例如:流程图、序列图、饼图等。
在 Hextra 中使用 Mermain 就像使用代码块一样简单:
````markdown
```mermaid
graph TD;
A-->B;
A-->C;
B-->D;
C-->D;
```
````
将呈现为:
```mermaid
graph TD;
A-->B;
A-->C;
B-->D;
C-->D;
```
Sequence diagram
```mermaid
sequenceDiagram
participant Alice
participant Bob
Alice->>John: Hello John, how are you?
loop Healthcheck
John->>John: Fight against hypochondria
end
Note right of John: Rational thoughts <br/>prevail!
John-->>Alice: Great!
John->>Bob: How about you?
Bob-->>John: Jolly good!
```
如需获取更多信息,转至 [Mermaid Documentation](https://mermaid-js.github.io/mermaid/#/)。

View File

@ -0,0 +1,59 @@
---
title: "LaTeX 公式"
weight: 4
math: true
---
$\KaTeX$ 用于呈现 LaTeX 数学表达式。可在 `frontmatter``math` 设置为 `true` 来启用。
<!--more-->
```yaml {filename="Markdown"}
---
title: "My Page with LaTeX"
math: true
---
```
启用后KaTeX 中的脚本,样式表和字体将自动包含在你的网站中。这样就可以在 Markdown 内容中使用 LaTeX 数学表达式。
## 示例
Markdown 内容支持行内和独立段落的 LaTeX 数学表达式。
### 行内
```markdown {filename="page.md"}
This $\sigma(z) = \frac{1}{1 + e^{-z}}$ is inline.
```
This $\sigma(z) = \frac{1}{1 + e^{-z}}$ is inline.
### 独立段落
```markdown {filename="page.md"}
$$F(\omega) = \int_{-\infty}^{\infty} f(t) e^{-j\omega t} \, dt$$
```
将被渲染为:
$$F(\omega) = \int_{-\infty}^{\infty} f(t) e^{-j\omega t} \, dt$$
## 支持的功能
有关支持的符号列表,转至 [KaTeX 支持的公式](https://katex.org/docs/supported.html)。
## 化学表达式
通过 [mhchem](https://mhchem.github.io/MathJax-mhchem/) 支持化学表达式。
行内:$\ce{H2O}$ 是水。
独立段落:
```markdown {filename="page.md"}
$$\ce{Hg^2+ ->[I-] HgI2 ->[I-] [Hg^{II}I4]^2-}$$
```
$$\ce{Hg^2+ ->[I-] HgI2 ->[I-] [Hg^{II}I4]^2-}$$

View File

@ -46,7 +46,7 @@ Tables aren't part of the core Markdown spec, but Hugo supports them out-of-the-
### Code Blocks
{{< cards >}}
{{< card link="/docs/guide/syntax-highlighting" title="Syntax Highlighting" icon="sparkles" >}}
{{< card link="../../guide/syntax-highlighting" title="Syntax Highlighting" icon="sparkles" >}}
{{< /cards >}}
### Lists

View File

@ -0,0 +1,105 @@
---
title: Markdown
weight: 2
---
Hugo 支持 [Markdown](https://en.wikipedia.org/wiki/Markdown) 来书写内容,创建列表等。本页将向你展示一些最常见的 Markdown 语法示例。
<!--more-->
## Markdown 示例
### 文本样式
| Style | Syntax | Example | Output |
| -------- | -------- | ------ | ------ |
| Bold | `**bold text**` | `**bold text**` | **bold text** |
| Italic | `*italicized text*` | `*italicized text* | *italicized text* |
| Strikethrough | `~~strikethrough text~~` | `~~strikethrough text~~` | ~~strikethrough text~~ |
| Subscript | `<sub></sub>` | `This is a <sub>subscript</sub> text` | This is a <sub>subscript</sub> text |
| Superscript | `<sup></sup>` | `This is a <sup>superscript</sup> text` | This is a <sup>superscript</sup> text |
### 引用
带角标的块引用:
> Don't communicate by sharing memory, share memory by communicating.<br>
> — <cite>Rob Pike[^1]</cite>
[^1]: The above quote is excerpted from Rob Pike's [talk](https://www.youtube.com/watch?v=PAAkCSZUG1c) during Gopherfest, November 18, 2015.
### 表格
表格并非核心 Markdown 规范,但 Hugo 支持开箱即用的表格:
Name | Age
--------|------
Bob | 27
Alice | 23
#### Markdown 表格中的内联
| Italics | Bold | Code |
| -------- | -------- | ------ |
| *italics* | **bold** | `code` |
### 代码块
{{< cards >}}
{{< card link="../../guide/syntax-highlighting" title="Syntax Highlighting" icon="sparkles" >}}
{{< /cards >}}
### 列表
#### 有序列表
1. First item
2. Second item
3. Third item
#### 无序列表
* List item
* Another item
* And another item
#### 嵌套列表
* Fruit
* Apple
* Orange
* Banana
* Dairy
* Milk
* Cheese
### 图片
![](https://source.unsplash.com/featured/800x600?landscape)
带有标题:
![](https://source.unsplash.com/featured/800x600?landscape "Unsplash Landscape")
## 配置
Hugo 使用 [Goldmark](https://github.com/yuin/goldmark) 解析 Markdown。
Markdown 渲染可以在 `hugo.yaml` 中的 `markup.goldmark` 中配置。以下是Hextra的默认配置
```yaml {filename="hugo.yaml"}
markup:
goldmark:
renderer:
unsafe: true
highlight:
noClasses: false
```
如需了解更多选项,转至 [Configure Markup](https://gohugo.io/getting-started/configuration-markup/)。
## 参考资料
* [Markdown Guide](https://www.markdownguide.org/)
* [Markdown Cheatsheet](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet)
* [Markdown Tutorial](https://www.markdowntutorial.com/)
* [Markdown Reference](https://commonmark.org/help/)

View File

@ -1,6 +1,7 @@
---
title: Organize Files
weight: 1
prev: /docs/guide
---
## Directory Structure
@ -62,3 +63,63 @@ weight: 2
## Configure Content Directory
If we need to use a different directory for our content, we can do so by setting the [`contentDir`](https://gohugo.io/getting-started/configuration/#contentdir) parameter in our site configuration file.
## Add Images
To add images, the easiest way is to put the image files in the same directory as the Markdown file.
For example, add an image file `image.png` alongside the `my-page.md` file:
{{< filetree/container >}}
{{< filetree/folder name="content" >}}
{{< filetree/folder name="docs" >}}
{{< filetree/file name="my-page.md" >}}
{{< filetree/file name="image.png" >}}
{{< /filetree/folder >}}
{{< /filetree/folder >}}
{{< /filetree/container >}}
Then, we can use the following Markdown syntax to add the image to the content:
```markdown {filename="content/docs/my-page.md"}
![](image.png)
```
We can also utilize the [page bundles][page-bundles] feature of Hugo to organize the image files together with the Markdown file. To achieve that, turn the `my-page.md` file into a directory `my-page` and put the content into a file named `index.md`, and put the image files inside the `my-page` directory:
{{< filetree/container >}}
{{< filetree/folder name="content" >}}
{{< filetree/folder name="docs" >}}
{{< filetree/folder name="my-page" >}}
{{< filetree/file name="index.md" >}}
{{< filetree/file name="image.png" >}}
{{< /filetree/folder >}}
{{< /filetree/folder >}}
{{< /filetree/folder >}}
{{< /filetree/container >}}
```markdown {filename="content/docs/my-page/index.md"}
![](image.png)
```
Alternatively, we can also put the image files in the `static` directory, which will make the images available for all pages:
{{< filetree/container >}}
{{< filetree/folder name="static" >}}
{{< filetree/folder name="images" >}}
{{< filetree/file name="image.png" >}}
{{< /filetree/folder >}}
{{< /filetree/folder >}}
{{< filetree/folder name="content" >}}
{{< filetree/folder name="docs" >}}
{{< filetree/file name="my-page.md" >}}
{{< /filetree/folder >}}
{{< /filetree/folder >}}
{{< /filetree/container >}}
Note that the image path begins with a slash `/` and is relative to the static directory:
```markdown {filename="content/docs/my-page.md"}
![](/images/image.png)
```
[page-bundles]: https://gohugo.io/content-management/page-bundles/#leaf-bundles

View File

@ -0,0 +1,65 @@
---
title: 目录结构
weight: 1
prev: /docs/guide
---
## 目录结构
默认情况下Hugo 在 `context` 目录中搜索 Markdown 文件,目录的结构决定了网站的最终输出结构。
以示例网站为例:
<!--more-->
{{< filetree/container >}}
{{< filetree/folder name="content" >}}
{{< filetree/file name="_index.md" >}}
{{< filetree/folder name="docs" state="open" >}}
{{< filetree/file name="_index.md" >}}
{{< filetree/file name="getting-started.md" >}}
{{< filetree/folder name="guide" state="open" >}}
{{< filetree/file name="_index.md" >}}
{{< filetree/file name="organize-files.md" >}}
{{< /filetree/folder >}}
{{< /filetree/folder >}}
{{< filetree/folder name="blog" state="open" >}}
{{< filetree/file name="_index.md" >}}
{{< filetree/file name="post-1.md" >}}
{{< /filetree/folder >}}
{{< /filetree/folder >}}
{{< /filetree/container >}}
每个 `_index.md` 文件都是相应部分的索引页,其他 Markdown 文件则是常规页面。
```
content
├── _index.md // <- /
├── docs
│ ├── _index.md // <- /docs/
│ ├── getting-started.md // <- /docs/getting-started/
│ └── guide
│ ├── _index.md // <- /docs/guide/
│ └── organize-files.md // <- /docs/guide/organize-files/
└── blog
├── _index.md // <- /blog/
└── post-1.md // <- /blog/post-1/
```
## 侧边栏导航
侧边栏导航是根据内容组织的字母顺序自动生成的。要手动配置侧边栏顺序,可以在 Markdown 文件的 `frontmatter ` 中使用 `weight` 配置。
```yaml {filename="content/docs/guide/_index.md"}
---
title: Guide
weight: 2
---
```
{{< callout emoji="">}}
建议侧边栏不要太深。如果内容太多,请考虑 **将它们分成多个部分**。
{{< /callout >}}
## 配置内容目录
如果需要为的内容使用不同的目录,可以在站点配置文件中设置 [`contentDir`](https://gohugo.io/getting-started/configuration/#contentdir) 来实现。

View File

@ -1,6 +1,8 @@
---
title: Shortcodes
weight: 9
prev: /docs/guide/diagrams
next: /docs/guide/shortcodes/callout
---
[Hugo Shortcodes](https://gohugo.io/content-management/shortcodes/) are simple snippets inside your content files calling built-in or custom templates.
@ -9,8 +11,9 @@ Hextra provides a collection of beautiful shortcodes to enhance your content.
{{< cards >}}
{{< card link="callouts" title="Callouts" icon="warning" >}}
{{< card link="callout" title="Callout" icon="warning" >}}
{{< card link="cards" title="Cards" icon="card" >}}
{{< card link="details" title="Details" icon="chevron-right" >}}
{{< card link="filetree" title="FileTree" icon="folder-tree" >}}
{{< card link="icon" title="Icon" icon="badge-check" >}}
{{< card link="steps" title="Steps" icon="one" >}}

View File

@ -0,0 +1,19 @@
---
title: 短代码
weight: 9
prev: /docs/guide/diagrams
next: /docs/guide/shortcodes/callout
---
[Hugo 短代码](https://gohugo.io/content-management/shortcodes/) 是你的内容文件中调用内置或自定义模板的简单片段。
Hextra 提供了一系列美观的短代码以增强你的内容。
{{< cards >}}
{{< card link="callout" title="注意事项" icon="warning" >}}
{{< card link="cards" title="卡片" icon="card" >}}
{{< card link="filetree" title="文件树" icon="folder-tree" >}}
{{< card link="icon" title="图标" icon="badge-check" >}}
{{< card link="steps" title="步骤" icon="one" >}}
{{< card link="tabs" title="标签" icon="collection" >}}
{{< /cards >}}

View File

@ -1,10 +1,15 @@
---
title: Callout Component
linkTitle: Callout
aliases:
- callouts
prev: /docs/guide/shortcodes
---
A built-in component to show important information to the reader.
<!--more-->
## Example
{{< callout emoji="👾">}}

View File

@ -6,20 +6,21 @@ linkTitle: Cards
## Example
{{< cards >}}
{{< card link="/" title="Callout" icon="warning" >}}
{{< card link="../callout" title="Callout" icon="warning" >}}
{{< card link="/" title="No Icon" >}}
{{< /cards >}}
{{< cards >}}
{{< card link="/" title="Image Card" image="https://source.unsplash.com/featured/800x600?landscape" subtitle="Unsplash Landscape" >}}
{{< card link="/" title="Local Image" image="/images/card-image-unprocessed.jpg" subtitle="Raw image under static directory." >}}
{{< card link="/" title="Local Image" image="images/space.jpg" subtitle="Image under assets directory, processed by Hugo." method="Resize" options="600x q80 webp" >}}
{{< /cards >}}
## Usage
```
{{</* cards */>}}
{{</* card link="/" title="Callout" icon="warning" */>}}
{{</* card link="../callout" title="Callout" icon="warning" */>}}
{{</* card link="/" title="No Icon" */>}}
{{</* /cards */>}}
```
@ -27,5 +28,37 @@ linkTitle: Cards
```
{{</* cards */>}}
{{</* card link="/" title="Image Card" image="https://source.unsplash.com/featured/800x600?landscape" subtitle="Unsplash Landscape" */>}}
{{</* card link="/" title="Local Image" image="/images/card-image-unprocessed.jpg" subtitle="Raw image under static directory." */>}}
{{</* card link="/" title="Local Image" image="images/space.jpg" subtitle="Image under assets directory, processed by Hugo." method="Resize" options="600x q80 webp" */>}}
{{</* /cards */>}}
```
## Card Parameters
| Parameter | Description |
|----------- |---------------------------------------|
| `link` | URL (internal or external). |
| `title` | Title heading for the card. |
| `subtitle` | Subtitle heading (supports Markdown). |
| `icon` | Name of the icon. |
## Image Card
Additionally, the card supports adding image and processing through these parameters:
| Parameter | Description |
|----------- |---------------------------------------------|
| `image` | Specifies the image URL for the card. |
| `method` | Sets Hugo's image processing method. |
| `options` | Configures Hugo's image processing options. |
Card supports three kinds of images:
1. Remote image: the full URL in the `image` parameter.
2. Static image: use the relative path in Hugo's `static/` directory.
3. Processed image: use the relative path in Hugo's `assets/` directory.
Hextra auto-detects if image processing is needed during build and applies the `options` parameter or default settings (Resize, 800x, Quality 80, WebP Format).
It currently supports these `method`: `Resize`, `Fit`, `Fill` and `Crop`.
For more on Hugo's built in image processing commands, methods, and options see their [Image Processing Documentation](https://gohugo.io/content-management/image-processing/).

View File

@ -0,0 +1,43 @@
---
title: Details
---
A built-in component to display a collapsible content.
<!--more-->
## Example
{{% details title="Details" %}}
This is the content of the details.
Markdown is **supported**.
{{% /details %}}
{{% details title="Click me to reveal" closed="true" %}}
This will be hidden by default.
{{% /details %}}
## Usage
````
{{%/* details title="Details" */%}}
This is the content of the details.
Markdown is **supported**.
{{%/* /details */%}}
````
````
{{%/* details title="Click me to reveal" closed="true" */%}}
This will be hidden by default.
{{%/* /details */%}}
````

View File

@ -29,6 +29,7 @@ Put Markdown h3 header within `steps` shortcode.
```
{{%/* steps */%}}
### Step 1
This is the first step.
@ -36,5 +37,6 @@ This is the first step.
### Step 2
This is the second step.
{{%/* /steps */%}}
```

View File

@ -1,5 +1,6 @@
---
title: Tabs
next: /docs/advanced/
---
## Example
@ -49,3 +50,44 @@ The `YAML` tab will be selected by default.
{{< tab >}}**TOML**: TOML aims to be a minimal configuration file format that's easy to read due to obvious semantics.{{< /tab >}}
{{< /tabs >}}
### Use Markdown
Markdown syntax including code block is also supported:
````
{{</* tabs items="JSON,YAML,TOML" */>}}
{{</* tab */>}}
```json
{ "hello": "world" }
```
{{</* /tab */>}}
... add other tabs similarly
{{</* /tabs */>}}
````
{{< tabs items="JSON,YAML,TOML" >}}
{{< tab >}}
```json
{ "hello": "world" }
```
{{< /tab >}}
{{< tab >}}
```yaml
hello: world
```
{{< /tab >}}
{{< tab >}}
```toml
hello = "world"
```
{{< /tab >}}
{{< /tabs >}}

View File

@ -0,0 +1,89 @@
---
title: "代码高亮"
weight: 3
---
Hugo 使用 [Chroma](https://github.com/alecthomas/chroma),一种纯 Golang 实现的代码高亮渲染器。
建议对 Markdown 内容中的代码块使用反引号,例如:
<!--more-->
````markdown {filename="Markdown"}
```python
def say_hello():
print("Hello!")
```
````
将呈现为:
```python
def say_hello():
print("Hello!")
```
## 特性
### 文件名
要向代码块添加文件名或标题,请设置 `filename`
````markdown {filename="Markdown"}
```python {filename="hello.py"}
def say_hello():
print("Hello!")
```
````
```python {filename="hello.py"}
def say_hello():
print("Hello!")
```
### 行号
如需设置行号,将 `linenos` 设置为 `table`,并将 `linenostart` 设置为起始行号:
````markdown {filename="Markdown"}
```python {linenos=table,linenostart=42}
def say_hello():
print("Hello!")
```
````
```python {linenos=table,linenostart=42}
def say_hello():
print("Hello!")
```
### 高亮行
显示高亮行,设置 `hl_lines` 为行号:
````markdown {filename="Markdown"}
```python {linenos=table,hl_lines=[2,4],linenostart=1,filename="hello.py"}
def say_hello():
print("Hello!")
def main():
say_hello()
```
````
```python {linenos=table,hl_lines=[2,4],linenostart=1,filename="hello.py"}
def say_hello():
print("Hello!")
def main():
say_hello()
```
### 复制按钮
默认情况下,代码块复制按钮已自动启用。
## 支持的编程语言
如需了解支持的编程语言,转至 [Chroma's documentation](https://github.com/alecthomas/chroma#supported-languages)。

View File

@ -0,0 +1,18 @@
---
title: Showcase
description: "Open source projects powered by Hextra."
toc: false
layout: wide
---
<div class="mt-4"></div>
<p class="mb-12 text-center text-lg text-gray-500 dark:text-gray-400">
Open source projects powered by Hextra.
</p>
{{< cards >}}
{{< card link="https://getporter.org/" title="Porter" image="https://repository-images.githubusercontent.com/155893691/aa249c80-fcf3-11ea-93b0-30079e8d7de4" imageStyle="object-fit:cover; aspect-ratio:16/9;" >}}
{{< card link="https://lutheranconfessions.org/" title="LutheranConfessions" image="https://github.com/imfing/hextra/assets/5097752/ad6625e4-88cd-4cad-b102-5399997d0359" imageStyle="object-fit:cover; aspect-ratio:16/9;" >}}
{{< card link="/" title="Hextra Starter Template" image="https://user-images.githubusercontent.com/5097752/263551418-c403b9a9-a76c-47a6-8466-513d772ef0b7.jpg" imageStyle="object-fit:cover; aspect-ratio:16/9;" >}}
{{< /cards >}}

View File

@ -5,7 +5,9 @@ title: "Hextra"
enableRobotsTXT: true
enableGitInfo: true
# enableEmoji: false
# hasCJKLanguage: true
hasCJKLanguage: true
# googleAnalytics: G-XXXXXXXXXX
outputs:
home: [HTML]
@ -22,11 +24,16 @@ languages:
languageName: 日本語
weight: 2
title: "Hextra テーマ"
zh-cn:
languageName: 简体中文
languageCode: zh-CN
weight: 3
title: Hextra
module:
hugoVersion:
extended: true
min: "0.111.0"
min: "0.112.0"
workspace: hugo.work
imports:
@ -47,20 +54,24 @@ menu:
name: Documentation
pageRef: /docs
weight: 1
- identifier: showcase
name: Showcase
pageRef: /showcase
weight: 2
- identifier: blog
name: Blog
pageRef: /blog
weight: 2
weight: 3
- identifier: about
name: About
pageRef: /about
weight: 3
- name: Search
weight: 4
- name: Search
weight: 5
params:
type: search
- name: GitHub
weight: 5
weight: 6
url: "https://github.com/imfing/hextra"
params:
icon: github
@ -89,20 +100,55 @@ params:
logo:
path: images/logo.svg
dark: images/logo-dark.svg
# link: /
# width: 40
# height: 20
# link: /
width: wide
page:
# full (100%), wide (90rem), normal (1280px)
width: normal
theme:
# light | dark | system
default: system
displayToggle: true
footer:
displayCopyright: true
displayPoweredBy: true
width: normal
displayUpdatedDate: true
dateFormat: "January 2, 2006"
# Search
# flexsearch is enabled by default
search:
enable: true
type: flexsearch
flexsearch:
# index page by: content | summary | heading | title
index: content
editURL:
enable: true
base: "https://github.com/imfing/hextra/edit/main/exampleSite/content"
comments:
enable: false
type: giscus
# https://giscus.app/
giscus:
repo: imfing/hextra
repoId: R_kgDOJ9fJag
category: General
categoryId: DIC_kwDOJ9fJas4CY7gW
# mapping: pathname
# strict: 0
# reactionsEnabled: 1
# emitMetadata: 0
# inputPosition: top
# lang: en

View File

@ -11,6 +11,7 @@
"cite",
"code",
"del",
"details",
"div",
"em",
"figcaption",
@ -39,11 +40,11 @@
"path",
"pre",
"script",
"section",
"span",
"strong",
"style",
"sub",
"summary",
"sup",
"svg",
"table",
@ -80,17 +81,21 @@
"before:bg-gray-200",
"before:content-[\"\"]",
"before:content-['#']",
"before:content-['']",
"before:inline-block",
"before:inset-0",
"before:inset-y-1",
"before:mr-1",
"before:opacity-25",
"before:pointer-events-none",
"before:transition-transform",
"before:w-px",
"bg-black/[.05]",
"bg-blue-100",
"bg-clip-text",
"bg-gradient-to-b",
"bg-gradient-to-r",
"bg-gray-100",
"bg-neutral-50",
"bg-orange-50",
"bg-primary-100",
"bg-primary-400",
@ -107,6 +112,7 @@
"border-black/5",
"border-blue-200",
"border-gray-200",
"border-gray-500",
"border-l",
"border-orange-100",
"border-red-200",
@ -122,6 +128,7 @@
"content",
"contrast-more:border",
"contrast-more:border-current",
"contrast-more:border-gray-800",
"contrast-more:border-gray-900",
"contrast-more:border-neutral-400",
"contrast-more:border-primary-500",
@ -147,9 +154,11 @@
"contrast-more:text-gray-800",
"contrast-more:text-gray-900",
"contrast-more:underline",
"copy-icon",
"cursor-default",
"cursor-pointer",
"dark:before:bg-neutral-800",
"dark:before:invert",
"dark:bg-blue-900/30",
"dark:bg-dark",
"dark:bg-dark/50",
@ -165,6 +174,7 @@
"dark:block",
"dark:border-blue-200/30",
"dark:border-gray-100/20",
"dark:border-gray-400",
"dark:border-neutral-700",
"dark:border-neutral-800",
"dark:border-orange-400/30",
@ -178,9 +188,11 @@
"dark:hidden",
"dark:hover:bg-gray-100/5",
"dark:hover:bg-neutral-700",
"dark:hover:bg-neutral-800",
"dark:hover:bg-neutral-900",
"dark:hover:bg-primary-100/5",
"dark:hover:bg-primary-700",
"dark:hover:border-gray-100",
"dark:hover:border-gray-600",
"dark:hover:border-neutral-500",
"dark:hover:border-neutral-700",
@ -219,6 +231,8 @@
"data-[state=selected]:text-primary-600",
"decoration-from-font",
"duration-200",
"duration-75",
"ease-in",
"ease-in-out",
"filename",
"first:mt-0",
@ -237,7 +251,6 @@
"footnote-backref",
"footnote-ref",
"footnotes",
"from-gray-800",
"from-gray-900",
"gap-1",
"gap-2",
@ -250,12 +263,14 @@
"group-data-[theme=dark]:hidden",
"group-data-[theme=light]:hidden",
"group-hover/code:opacity-100",
"group-open:before:rotate-90",
"group/code",
"group/copybtn",
"grow",
"h-0",
"h-16",
"h-2",
"h-3.5",
"h-4",
"h-5",
"h-7",
@ -264,9 +279,11 @@
"hamburger-menu",
"hextra-card",
"hextra-cards",
"hextra-feature-card",
"hextra-filetree",
"hextra-filetree-folder",
"hextra-footer",
"hextra-scrollbar",
"hextra-sidebar-collapsible-button",
"hextra-toc",
"hidden",
@ -279,6 +296,7 @@
"hover:border-gray-200",
"hover:border-gray-300",
"hover:border-gray-400",
"hover:border-gray-900",
"hover:dark:bg-primary-500/10",
"hover:dark:text-primary-600",
"hover:opacity-60",
@ -305,14 +323,15 @@
"justify-start",
"language-options",
"language-switcher",
"last-of-type:mb-0",
"leading-5",
"leading-6",
"leading-7",
"leading-none",
"leading-tight",
"left-[24px]",
"left-[36px]",
"lg:grid-cols-3",
"lg:leading-[1.1]",
"line-clamp-3",
"list-none",
"lntable",
@ -356,6 +375,7 @@
"mb-16",
"mb-2",
"mb-4",
"mb-6",
"mb-8",
"md:aspect-[1.1/1]",
"md:h-[calc(100vh-var(--navbar-height)-var(--menu-height))]",
@ -397,6 +417,8 @@
"mx-auto",
"my-1.5",
"my-2",
"nav-container",
"nav-container-blur",
"next-error-h1",
"no-underline",
"not-prose",
@ -413,11 +435,11 @@
"overflow-y-auto",
"overscroll-contain",
"p-0.5",
"p-1",
"p-1.5",
"p-2",
"p-4",
"p-6",
"pb-6",
"pb-8",
"pb-[env(safe-area-inset-bottom)]",
"pb-px",
@ -426,8 +448,10 @@
"pl-[max(env(safe-area-inset-left),1.5rem)]",
"placeholder:text-gray-500",
"pointer-events-none",
"pr-2",
"pr-4",
"pr-[calc(env(safe-area-inset-right)-1.5rem)]",
"pr-[max(env(safe-area-inset-left),1.5rem)]",
"pr-[max(env(safe-area-inset-right),1.5rem)]",
"print:bg-transparent",
"print:hidden",
@ -462,6 +486,7 @@
"rtl:-ml-4",
"rtl:-rotate-180",
"rtl:before:right-0",
"rtl:before:rotate-180",
"rtl:left-1.5",
"rtl:left-3",
"rtl:md:right-auto",
@ -498,7 +523,6 @@
"sm:flex",
"sm:grid-cols-2",
"sm:items-start",
"sm:px-4",
"sm:text-xl",
"sm:w-[110%]",
"sr-only",
@ -524,6 +548,7 @@
"text-gray-800",
"text-gray-900",
"text-left",
"text-lg",
"text-orange-800",
"text-primary-800",
"text-red-900",

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 KiB

View File

@ -1,5 +1,9 @@
onThisPage: "On this page"
backToTop: "Scroll to top"
changeLanguage: "Change language"
changeTheme: "Change theme"
copyright: "© 2023 Hextra Project."
editThisPage: "Edit this page on GitHub →"
lastUpdated: "Last updated on"
copyright: "© 2023 Hextra Project."
onThisPage: "On this page"
readMore: "Read more →"
searchPlaceholder: "Search..."

7
i18n/es.yaml Normal file
View File

@ -0,0 +1,7 @@
onThisPage: "En esta página"
editThisPage: "Edita esta página en GitHub →"
lastUpdated: "Última actualización"
backToTop: "Subir al inicio"
copyright: "© 2023 Hextra Project."

9
i18n/ko.yaml Normal file
View File

@ -0,0 +1,9 @@
backToTop: "맨위로 스크롤"
changeLanguage: "언어변경"
changeTheme: "테마변경"
copyright: "© 2023 Hextra Project."
editThisPage: "Github에서 편집하기 →"
lastUpdated: "마지막 수정일자"
onThisPage: "페이지 목차"
readMore: "더보기 →"
searchPlaceholder: "검색..."

7
i18n/pt.yaml Normal file
View File

@ -0,0 +1,7 @@
onThisPage: "Nesta página"
editThisPage: "Edita esta página no GitHub →"
lastUpdated: "Última actualização"
backToTop: "Voltar ao topo"
copyright: "© 2023 Projecto Hextra."

5
i18n/sw.yaml Normal file
View File

@ -0,0 +1,5 @@
onThisPage: "Kwenye ukurasa huu"
editThisPage: "Hariri ukurasa huu kwenye GitHub →"
lastUpdated: "Ilisasishwa mwisho"
backToTop: "Tembeza hadi juu"
copyright: "© 2023 Hextra Project."

7
i18n/vi.yaml Normal file
View File

@ -0,0 +1,7 @@
onThisPage: "Ở trang này"
editThisPage: "Sửa trang này trên GitHub →"
lastUpdated: "Lần cuối cập nhật lúc"
backToTop: "Lướt lên đầu trang"
copyright: "© 2023 Hextra Project."

17
i18n/zh-cn.yaml Normal file
View File

@ -0,0 +1,17 @@
documentation: "文档"
blog: "博客"
about: "关于"
more: "更多"
hugoDocs: "Hugo 文档 ↗"
searchPlaceholder: "搜索文档..."
noResultsFound: "无结果"
onThisPage: "此页上"
editThisPage: "在 GitHub 上编辑此页 →"
lastUpdated: "最后更新于"
backToTop: "返回顶部"
copyright: "© 2023 Hextra Project."

15
i18n/zh-tw.yaml Normal file
View File

@ -0,0 +1,15 @@
documentation: "文檔"
blog: "博客"
about: "關於"
more: "更多"
hugoDocs: "Hugo 文檔 ↗"
searchPlaceholder: "搜索文檔..."
noResultsFound: "無結果"
onThisPage: "此頁上"
editThisPage: "在 GitHub 上編輯此頁 →"
lastUpdated: "最後更新於"
copyright: "© 2023 Hextra Project."

View File

@ -15,9 +15,13 @@
<pre><code id="code-block-{{ .Ordinal }}">{{ .Inner }}</code></pre>
{{- end -}}
<div class="opacity-0 transition group-hover/code:opacity-100 flex gap-1 absolute m-[11px] right-0 {{ if $filename }}top-8{{ else }}top-0{{ end }}">
<button class="code-copy-btn group/copybtn transition-all active:opacity-50 bg-primary-700/5 border border-black/5 text-gray-600 hover:text-gray-900 rounded-md p-1.5 dark:bg-primary-300/10 dark:border-white/10 dark:text-gray-400 dark:hover:text-gray-50" title="Copy code" data-clipboard-target="#code-block-{{ .Ordinal }}">
{{ partial "utils/icon.html" (dict "name" "copy" "attributes" "class=\"group-[.copied]/copybtn:hidden pointer-events-none h-4 w-4\"") }}
{{ partial "utils/icon.html" (dict "name" "check" "attributes" "class=\"hidden group-[.copied]/copybtn:block success-icon pointer-events-none h-4 w-4\"") }}
<button
class="code-copy-btn group/copybtn transition-all active:opacity-50 bg-primary-700/5 border border-black/5 text-gray-600 hover:text-gray-900 rounded-md p-1.5 dark:bg-primary-300/10 dark:border-white/10 dark:text-gray-400 dark:hover:text-gray-50"
title="Copy code"
data-clipboard-target="#code-block-{{ .Ordinal }}"
>
<div class="group-[.copied]/copybtn:hidden copy-icon pointer-events-none h-4 w-4"></div>
<div class="hidden group-[.copied]/copybtn:block success-icon pointer-events-none h-4 w-4"></div>
</button>
</div>
</div>

View File

@ -1,8 +1,27 @@
{{- if .Title -}}
{{- $alt := .PlainText | safeHTML -}}
{{- $lazyLoading := .Page.Site.Params.enableImagelazyLoading | default true -}}
{{- $dest := .Destination -}}
{{- $isRemote := not (urls.Parse $dest).Scheme -}}
{{- $isPage := and (eq .Page.Kind "page") (not .Page.BundleType) -}}
{{- $startsWithSlash := hasPrefix $dest "/" -}}
{{- $startsWithRelative := hasPrefix $dest "../" -}}
{{- if and $dest $isRemote -}}
{{- if $startsWithSlash -}}
{{/* Images under static directory */}}
{{- $dest = (relURL (strings.TrimPrefix "/" $dest)) -}}
{{- else if and $isPage (not $startsWithRelative) -}}
{{/* Images that are sibling to the individual page file */}}
{{ $dest = (printf "../%s" $dest) }}
{{- end -}}
{{- end -}}
{{- with .Title -}}
<figure>
<img src="{{ .Destination | safeURL }}" title="{{ .Title }}" alt="{{ .PlainText | safeHTML }}" loading="lazy" />
<figcaption>{{ .Title }}</figcaption>
<img src="{{ $dest | safeURL }}" title="{{ . }}" alt="{{ $alt }}" {{ if $lazyLoading }}loading="lazy"{{ end }} />
<figcaption>{{ . }}</figcaption>
</figure>
{{- else -}}
<img src="{{ .Destination | safeURL }}" alt="{{ .PlainText | safeHTML }}" loading="lazy" />
<img src="{{ $dest | safeURL }}" alt="{{ $alt }}" {{ if $lazyLoading }}loading="lazy"{{ end }} />
{{- end -}}

View File

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

View File

@ -1,5 +1,5 @@
{{ define "main" }}
<div class="mx-auto flex max-w-screen-xl">
<div class='mx-auto flex {{ partial "utils/page-width" . }}'>
{{ partial "sidebar.html" (dict "context" .) }}
{{ partial "toc.html" . }}
<article class="w-full break-words flex min-h-[calc(100vh-var(--navbar-height))] min-w-0 justify-center pb-8 pr-[calc(env(safe-area-inset-right)-1.5rem)]">
@ -10,6 +10,7 @@
</div>
<div class="mt-16"></div>
{{ partial "components/last-updated.html" . }}
{{ partial "components/comments.html" . }}
</main>
</article>
</div>

View File

@ -0,0 +1,43 @@
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>{{ .Site.Title }} {{ .Title }}</title>
<link>{{ .Permalink }}</link>
<description>Recent content {{ if ne .Title .Site.Title }}{{ with .Title }}in {{.}} {{ end }}{{ end }}on {{ .Site.Title }}</description>
<generator>Hugo -- gohugo.io</generator>{{ with .Site.LanguageCode }}
<language>{{.}}</language>{{end}}{{ with .Site.Author.email }}
<managingEditor>{{.}}{{ with $.Site.Author.name }} ({{.}}){{end}}</managingEditor>{{end}}{{ with .Site.Author.email }}
<webMaster>{{.}}{{ with $.Site.Author.name }} ({{.}}){{end}}</webMaster>{{end}}{{ with .Site.Copyright }}
<copyright>{{.}}</copyright>{{end}}{{ if not .Date.IsZero }}
<lastBuildDate>{{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }}</lastBuildDate>{{ end }}
{{ with .OutputFormats.Get "RSS" }}
{{ printf "<atom:link href=%q rel=\"self\" type=%q />" .Permalink .MediaType | safeHTML }}
{{ end }}
{{ if not $.Section }}
{{ $sections := .Site.Params.rss.sections | default (slice "blog") }}
{{ .Scratch.Set "rssPages" (first 50 (where $.Site.RegularPages "Type" "in" $sections )) }}
{{ else }}
{{ if $.Parent.IsHome }}
{{ .Scratch.Set "rssPages" (first 50 (where $.Site.RegularPages "Type" $.Section )) }}
{{ else }}
{{ .Scratch.Set "rssPages" (first 50 $.Pages) }}
{{ end }}
{{ end }}
{{ range (.Scratch.Get "rssPages") }}
<item>
<title>{{ .Title }}</title>
<link>{{ .Permalink }}</link>
<pubDate>{{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }}</pubDate>
{{ with .Site.Author.email }}<author>{{.}}{{ with $.Site.Author.name }} ({{.}}){{end}}</author>{{end}}
<guid>{{ .Permalink }}</guid>
<description>
{{ $img := (.Resources.ByType "image").GetMatch "*featured*" }}
{{ with $img }}
{{ $img := .Resize "640x" }}
{{ printf "<![CDATA[<img src=\"%s\" width=\"%d\" height=\"%d\"/>]]>" $img.Permalink $img.Width $img.Height | safeHTML }}
{{ end }}
{{ .Content | html }}
</description>
</item>
{{ end }}
</channel>
</rss>

View File

@ -1,14 +1,17 @@
{{ define "main" }}
<div class="mx-auto flex max-w-screen-xl">
<div class='mx-auto flex {{ partial "utils/page-width" . }}'>
{{ partial "sidebar.html" (dict "context" . "disableSidebar" true "displayPlaceholder" true) }}
{{ partial "toc.html" . }}
<article class="w-full break-words flex min-h-[calc(100vh-var(--navbar-height))] min-w-0 justify-center pb-8 pr-[calc(env(safe-area-inset-right)-1.5rem)]">
<main class="w-full min-w-0 max-w-6xl px-6 pt-4 md:px-12">
<br class="mt-1.5 text-sm" />
<h1 class="text-center mt-2 text-4xl font-bold tracking-tight text-slate-900 dark:text-slate-100">{{ .Title }}</h1>
<div class="mb-16"></div>
<div class="content">
{{ .Content }}
</div>
<div class="mt-16"></div>
{{ partial "components/comments.html" . }}
</main>
</article>
</div>

View File

@ -0,0 +1,12 @@
{{ define "main" }}
<div class="mx-auto flex max-w-[90rem]">
{{ partial "sidebar.html" (dict "context" . "disableSidebar" true "displayPlaceholder" false) }}
<article class="w-full break-words min-h-[calc(100vh-var(--navbar-height))] min-w-0 pt-4 pb-8 pl-[max(env(safe-area-inset-left),1.5rem)] pr-[max(env(safe-area-inset-left),1.5rem)]">
<br class="mt-1.5 text-sm" />
<h1 class="text-center mt-2 text-4xl font-bold tracking-tight text-slate-900 dark:text-slate-100">{{ .Title }}</h1>
<div class="content">
{{ .Content }}
</div>
</article>
</div>
{{ end }}

View File

@ -1,16 +1,18 @@
{{ define "main" }}
<div class="mx-auto flex max-w-screen-xl">
{{- $readMore := (T "readMore") | default "Read more →" -}}
<div class='mx-auto flex {{ partial "utils/page-width" . }}'>
{{ partial "sidebar.html" (dict "context" . "disableSidebar" true "displayPlaceholder" true) }}
<article class="w-full break-words flex min-h-[calc(100vh-var(--navbar-height))] min-w-0 justify-center pb-8 pr-[calc(env(safe-area-inset-right)-1.5rem)]">
<main class="w-full min-w-0 max-w-6xl px-6 pt-4 md:px-12">
<h1 class="text-4xl tracking-tighter text-center font-extrabold md:text-5xl mt-8 pb-6">{{ .Title }}</h1>
<br class="mt-1.5 text-sm" />
<h1 class="text-center mt-2 text-4xl font-bold tracking-tight text-slate-900 dark:text-slate-100">{{ .Title }}</h1>
<div class="content">{{ .Content }}</div>
{{ range .Pages.ByDate }}
{{ range .Pages.ByDate.Reverse }}
<div class="mb-10">
<h3><a style="color: inherit; text-decoration: none;" class="block font-semibold mt-8 text-2xl " href="{{ .RelPermalink }}">{{ .Title }}</a></h3>
<p class="opacity-80 mt-6 leading-7">
{{- partial "utils/page-description" . }}
<span class="inline-block"> <a class="text-[color:hsl(var(--primary-hue),100%,50%)] underline underline-offset-2 decoration-from-font" href="{{ .RelPermalink }}">Read more </a> </span>
<span class="inline-block"> <a class="text-[color:hsl(var(--primary-hue),100%,50%)] underline underline-offset-2 decoration-from-font" href="{{ .RelPermalink }}">{{ $readMore }}</a> </span>
</p>
<p class="opacity-50 text-sm mt-6 leading-7">{{ partial "utils/format-date" .Date }}</p>
</div>

View File

@ -1,5 +1,5 @@
{{ define "main" }}
<div class="mx-auto flex max-w-screen-xl">
<div class='mx-auto flex {{ partial "utils/page-width" . }}'>
{{ partial "sidebar.html" (dict "context" . "disableSidebar" true "displayPlaceholder" true) }}
{{ partial "toc.html" . }}
<article class="w-full break-words flex min-h-[calc(100vh-var(--navbar-height))] min-w-0 justify-center pb-8 pr-[calc(env(safe-area-inset-right)-1.5rem)]">
@ -28,6 +28,7 @@
{{ partial "components/last-updated.html" . }}
{{ .Scratch.Set "reversePagination" true }}
{{ partial "components/pager.html" . }}
{{ partial "components/comments.html" . }}
</main>
</article>
</div>

View File

@ -1,5 +1,5 @@
{{ define "main" }}
<div class="mx-auto flex max-w-screen-xl">
<div class='mx-auto flex {{ partial "utils/page-width" . }}'>
{{ partial "sidebar.html" (dict "context" .) }}
{{ partial "toc.html" . }}
<article class="w-full break-words flex min-h-[calc(100vh-var(--navbar-height))] min-w-0 justify-center pb-8 pr-[calc(env(safe-area-inset-right)-1.5rem)]">
@ -9,9 +9,9 @@
<h1>{{ .Title }}</h1>
{{ .Content }}
</div>
<div class="mt-16"></div>
{{ partial "components/last-updated.html" . }}
{{ partial "components/pager.html" . }}
{{ partial "components/comments.html" . }}
</main>
</article>
</div>

View File

@ -1,5 +1,5 @@
{{ define "main" }}
<div class="mx-auto flex max-w-screen-xl">
<div class='mx-auto flex {{ partial "utils/page-width" . }}'>
{{ partial "sidebar.html" (dict "context" .) }}
{{ partial "toc.html" . }}
<article class="w-full break-words flex min-h-[calc(100vh-var(--navbar-height))] min-w-0 justify-center pb-8 pr-[calc(env(safe-area-inset-right)-1.5rem)]">
@ -11,6 +11,7 @@
</div>
{{ partial "components/last-updated.html" . }}
{{ partial "components/pager.html" . }}
{{ partial "components/comments.html" . }}
</main>
</article>
</div>

View File

@ -1,118 +1,10 @@
{{ define "main" }}
<div class="mx-auto flex max-w-screen-xl">
<div class='mx-auto flex {{ partial "utils/page-width" . }}'>
{{ partial "sidebar.html" (dict "context" . "disableSidebar" true) }}
<div class="w-full break-words flex flex-col min-h-[calc(100vh-var(--navbar-height))] min-w-0 justify-start pb-8 pr-[calc(env(safe-area-inset-right)-1.5rem)]">
<section class="flex max-w-[90rem] flex-col items-start gap-2 px-6 sm:px-4 pt-8 md:pt-12">
<a
href="https://github.com/imfing/hextra"
target="_blank"
rel="noreferrer"
class="inline-flex items-center rounded-full gap-2 px-3 py-1 text-xs text-gray-600 dark:text-gray-400 bg-gray-100 dark:bg-neutral-800 dark:border-neutral-800 border hover:border-gray-400 dark:hover:text-gray-50 dark:hover:border-gray-600"
>
<div class="w-2 h-2 rounded-full bg-primary-400"></div>
<span>Free, open source</span>
{{- partial "utils/icon" (dict "name" "arrow-circle-right" "attributes" "height=14") -}}
</a>
<h1
class="text-4xl font-bold leading-tight tracking-tighter md:text-5xl lg:leading-[1.1] mt-6 bg-clip-text text-transparent bg-gradient-to-r from-gray-900 to-gray-600 dark:from-gray-100 dark:to-gray-400"
>
Build modern websites&nbsp;<br class="sm:block hidden" />
with Markdown and Hugo
</h1>
<p class="mt-4 text-xl text-gray-600 dark:text-gray-400 sm:text-xl">
Fast, batteries-included Hugo theme <br class="sm:block hidden" />
for creating beautiful static websites.
</p>
<div class="mt-8">
{{- $docsURL := "docs" | relURL -}}
<a
href="{{ $docsURL }}"
class="font-medium cursor-pointer px-6 py-3 text-white bg-primary-600 hover:bg-primary-700 focus:outline-none focus:ring-4 focus:ring-primary-300 rounded-full text-center mr-2 mb-2 dark:bg-primary-600 dark:hover:bg-primary-700 dark:focus:ring-primary-800"
>
Get Started
</a>
</div>
</section>
<section class="flex max-w-[90rem] flex-col items-start gap-2 px-6 sm:px-4 pt-8 pb-8">
<h2 class="mt-12 text-2xl font-bold bg-clip-text text-transparent bg-gradient-to-b from-gray-800 to-gray-600 dark:from-gray-100 dark:to-gray-400">What's in Hextra?</h2>
<div class="mt-6 grid sm:grid-cols-2 lg:grid-cols-3 grid-cols-1 gap-4 w-full">
{{ template "hextra-feature-card" (dict
"title" "Fast and Full-featured"
"subtitle" "Simple and easy to use, yet powerful and feature-rich. "
"class" "aspect-auto md:aspect-[1.1/1] max-md:min-h-[340px]"
"image" "images/hextra-doc.webp"
"imageClass" "top-[40%] left-[24px] w-[180%] sm:w-[110%] dark:opacity-80"
"style" "background: radial-gradient(ellipse at 50% 80%,rgba(194,97,254,0.15),hsla(0,0%,100%,0));"
)
}}
{{ template "hextra-feature-card" (dict
"title" "Markdown is All You Need"
"subtitle" "Compose with just Markdown. Enrich with Shortcode components."
"class" "aspect-auto md:aspect-[1.1/1] max-lg:min-h-[340px]"
"image" "images/hextra-markdown.webp"
"imageClass" "top-[40%] left-[36px] w-[180%] sm:w-[110%] dark:opacity-80"
"style" "background: radial-gradient(ellipse at 50% 80%,rgba(142,53,74,0.15),hsla(0,0%,100%,0));"
)
}}
{{ template "hextra-feature-card" (dict
"title" "Full Text Search"
"subtitle" "Built-in full text search with FlexSearch, no extra setup required."
"class" "aspect-auto md:aspect-[1.1/1] max-md:min-h-[340px]"
"image" "images/hextra-search.webp"
"imageClass" "top-[40%] left-[36px] w-[110%] sm:w-[110%] dark:opacity-80"
"style" "background: radial-gradient(ellipse at 50% 80%,rgba(221,210,59,0.15),hsla(0,0%,100%,0));"
)
}}
{{ template "hextra-feature-card" (dict
"title" "Lightweight as a Feather"
"subtitle" "No dependency or Node.js is needed to use Hextra. Powered by Hugo, one of *the fastest* static site generators, building your site in just seconds with a single binary."
)
}}
{{ template "hextra-feature-card" (dict
"title" "Reponsive with Dark Mode Included"
"subtitle" "Looks great on different screen sizes. Built-in dark mode support, with auto-switching based on user's system preference."
)
}}
{{ template "hextra-feature-card" (dict
"title" "Build and Host for Free"
"subtitle" "Build with GitHub Actions, and host for free on GitHub Pages. Alternatively it can be hosted on any static hosting service."
)
}}
{{ template "hextra-feature-card" (dict
"title" "Multi-Language Made Easy"
"subtitle" "Create multi-language pages by just adding locales suffix to the Markdown file. Adding i18n support to your site is intuitive."
)
}}
{{ template "hextra-feature-card" (dict
"title" "And Much More..."
"subtitle" "Syntax highlighting / Table of contents / SEO / RSS / LaTeX / Mermaid / Customizable / and more..."
)
}}
</div>
</section>
<div class="w-full break-words min-h-[calc(100vh-var(--navbar-height))] min-w-0 pb-8 pt-8 md:pt-12 pl-[max(env(safe-area-inset-left),1.5rem)] pr-[max(env(safe-area-inset-left),1.5rem)]">
<div class="flex flex-col items-start">
{{ .Content }}
</div>
</div>
</div>
{{ end }}
{{- define "hextra-feature-card" -}}
{{- $title := .title -}}
{{- $subtitle := .subtitle -}}
{{- $class := .class -}}
{{- $image := .image -}}
{{- $imageClass := .imageClass -}}
{{- $style := .style -}}
<div
{{ with $style }}style="{{ . | safeCSS }}"{{ end }}
class="{{ $class }} relative overflow-hidden rounded-3xl border border-gray-200 hover:border-gray-300 dark:border-neutral-800 dark:hover:border-neutral-700 before:pointer-events-none before:absolute before:inset-0 before:bg-glass-gradient"
>
<div class="relative w-full p-6">
<h3 class="text-2xl font-medium leading-6 mb-2">{{ $title }}</h3>
<p class="text-gray-500 text-sm leading-6">{{ $subtitle | markdownify }}</p>
</div>
{{- with $image -}}
<img src="{{ . }}" class="absolute max-w-none {{ $imageClass }}" alt="{{ $title }}" />
{{- end -}}
</div>
{{- end -}}

View File

@ -1,5 +1,5 @@
{{ define "main" }}
<div class="mx-auto flex max-w-screen-xl">
<div class='mx-auto flex {{ partial "utils/page-width" . }}'>
{{ partial "sidebar.html" (dict "context" . "disableSidebar" true "displayPlaceholder" true) }}
{{ partial "toc.html" . }}
<article class="w-full break-words flex min-h-[calc(100vh-var(--navbar-height))] min-w-0 justify-center pb-8 pr-[calc(env(safe-area-inset-right)-1.5rem)]">

View File

@ -0,0 +1,11 @@
{{- $enableComments := site.Params.comments.enable | default false -}}
{{ if not (eq .Params.comments nil) }}
{{ $enableComments = .Params.comments }}
{{ end }}
{{- if $enableComments -}}
{{- if eq site.Params.comments.type "giscus" -}}
{{ partial "components/giscus.html" . }}
{{- end -}}
{{- end -}}

View File

@ -0,0 +1,62 @@
{{- $lang := site.Language.LanguageCode | default `en` -}}
{{- with site.Params.comments.giscus -}}
<script>
/*
* "preferred color scheme" theme in giscus works using "prefers-color-scheme" in media query.
* but, hugo's theme switch function works by using "color-theme" in local storage.
* This solution was created with reference to:
* https://github.com/giscus/giscus/issues/336#issuecomment-1214366281
*/
function getGiscusTheme() {
return localStorage.getItem("color-theme");
}
function setGiscusTheme() {
function sendMessage(message) {
const iframe = document.querySelector('iframe.giscus-frame');
if (!iframe) return;
iframe.contentWindow.postMessage({ giscus: message }, 'https://giscus.app');
}
sendMessage({
setConfig: {
theme: getGiscusTheme(),
},
});
}
document.addEventListener('DOMContentLoaded', function () {
const giscusAttributes = {
"src": "https://giscus.app/client.js",
"data-repo": "{{ .repo }}",
"data-repo-id": "{{ .repoId }}",
"data-category": "{{ .category }}",
"data-category-id": "{{ .categoryId }}",
"data-mapping": "{{ .mapping | default `pathname` }}",
"data-strict": "{{ (string .strict) | default 0 }}",
"data-reactions-enabled": "{{ (string .reactionsEnabled) | default 1 }}",
"data-emit-metadata": "{{ (string .emitMetadata) | default 0 }}",
"data-input-position": "{{ .inputPosition | default `top` }}",
"data-theme": getGiscusTheme(),
"data-lang": "{{ .lang | default $lang }}",
"crossorigin": "anonymous",
"async": "",
};
// Dynamically create script tag
const giscusScript = document.createElement("script");
Object.entries(giscusAttributes).forEach(([key, value]) => giscusScript.setAttribute(key, value));
document.getElementById('giscus').appendChild(giscusScript);
// Update giscus theme when theme switcher is clicked
const toggles = document.querySelectorAll(".theme-toggle");
if (toggles) {
toggles.forEach(toggle => toggle.addEventListener('click', setGiscusTheme));
}
});
</script>
<div id="giscus"></div>
{{- else -}}
{{ warnf "giscus is not configured" }}
{{- end -}}

View File

@ -5,15 +5,23 @@
{{- $prev := cond $reversePagination .PrevInSection .NextInSection -}}
{{- $next := cond $reversePagination .NextInSection .PrevInSection -}}
{{- with .Params.prev -}}
{{- with $.Site.GetPage . -}}
{{- if $reversePagination }}{{ $next = . }}{{ else }}{{ $prev = . }}{{ end -}}
{{- if eq .Params.prev false }}
{{- if $reversePagination }}{{ $next = false }}{{ else }}{{ $prev = false }}{{ end -}}
{{ else }}
{{- with .Params.prev -}}
{{- with $.Site.GetPage . -}}
{{- if $reversePagination }}{{ $next = . }}{{ else }}{{ $prev = . }}{{ end -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{- with .Params.next -}}
{{- with $.Site.GetPage . -}}
{{- if $reversePagination }}{{ $prev = . }}{{ else }}{{ $next = . }}{{ end -}}
{{- if eq .Params.next false }}
{{- if $reversePagination }}{{ $prev = false }}{{ else }}{{ $next = false }}{{ end -}}
{{ else }}
{{- with .Params.next -}}
{{- with $.Site.GetPage . -}}
{{- if $reversePagination }}{{ $prev = . }}{{ else }}{{ $next = . }}{{ end -}}
{{- end -}}
{{- end -}}
{{- end -}}

View File

@ -1,22 +1,34 @@
{{- $enableFooterSwitches := .Scratch.Get "enableFooterSwitches" | default false -}}
{{- $displayThemeToggle := site.Params.theme.displayToggle | default true -}}
{{- $copyright := (T "copyright") | default "© 2023 Hextra." -}}
{{- $footerWidth := "max-w-screen-xl" -}}
{{- with .Site.Params.footer.width -}}
{{ if eq . "wide" -}}
{{ $footerWidth = "max-w-[90rem]" -}}
{{ else if eq . "full" -}}
{{ $footerWidth = "max-w-full" -}}
{{ end -}}
{{- end -}}
<footer class="hextra-footer bg-gray-100 pb-[env(safe-area-inset-bottom)] dark:bg-neutral-900 print:bg-transparent">
{{- if $enableFooterSwitches }}
<div class="mx-auto flex max-w-screen-xl gap-2 py-2 px-4">
{{- if $enableFooterSwitches -}}
<div class="mx-auto flex gap-2 py-2 px-4 {{ $footerWidth }}">
{{- partial "language-switch.html" (dict "context" .) -}}
{{- partial "theme-toggle.html" -}}
{{- with $displayThemeToggle }}{{ partial "theme-toggle.html" }}{{ end -}}
</div>
{{ end -}}
<hr class="dark:border-neutral-800" />
{{- if or site.IsMultiLingual $displayThemeToggle -}}
<hr class="dark:border-neutral-800" />
{{- end -}}
{{- end -}}
<div
class="mx-auto flex max-w-screen-xl justify-center py-12 pl-[max(env(safe-area-inset-left),1.5rem)] pr-[max(env(safe-area-inset-right),1.5rem)] text-gray-600 dark:text-gray-400 md:justify-start"
class="{{ $footerWidth }} mx-auto flex justify-center py-12 pl-[max(env(safe-area-inset-left),1.5rem)] pr-[max(env(safe-area-inset-right),1.5rem)] text-gray-600 dark:text-gray-400 md:justify-start"
>
<div class="flex w-full flex-col items-center sm:items-start">
{{- if (.Site.Params.footer.displayPoweredBy | default true) }}<div class="font-semibold">{{ template "theme-credit" . }}</div>{{ end }}
{{- if .Site.Params.footer.displayCopyright }}<p class="mt-6 text-xs">{{ $copyright }}</p>{{ end }}
{{- if .Site.Params.footer.displayCopyright }}<div class="mt-6 text-xs">{{ $copyright | markdownify }}</div>{{ end }}
</div>
</div>
</footer>

View File

@ -0,0 +1,13 @@
{{ with .Site.GoogleAnalytics }}
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id={{ . }}"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag("js", new Date());
gtag("config", "{{ . }}");
</script>
{{ end }}

View File

@ -1,14 +1,25 @@
{{ if and (not hugo.IsProduction) (eq hugo.Environment "theme")}}
{{ $styles := resources.Get "css/styles.css" }}
{{ $styles = $styles | resources.PostCSS (dict "inlineImports" true) }}
{{- if and (not hugo.IsProduction) (eq hugo.Environment "theme") }}
{{- $styles := resources.Get "css/styles.css" }}
{{- $styles = $styles | resources.PostCSS (dict "inlineImports" true) }}
<link href="{{ $styles.RelPermalink }}" rel="stylesheet" />
{{ else }}
{{ $styles := resources.Get "css/compiled/main.css" }}
{{ $styles = $styles | minify | fingerprint | resources.PostProcess }}
<link rel="preload" href="{{ $styles.RelPermalink }}" as="style" />
<link href="{{ $styles.RelPermalink }}" rel="stylesheet" integrity="{{ $styles.Data.Integrity }}" />
{{ end }}
{{- else }}
{{- $styles := resources.Get "css/compiled/main.css" -}}
{{ $custom := resources.Get "css/custom.css" }}
{{ $custom = $custom | minify | fingerprint }}
<link href="{{ $custom.RelPermalink }}" rel="stylesheet" integrity="{{ $custom.Data.Integrity }}" />
{{- if hugo.IsProduction }}
{{- $styles = $styles | minify | fingerprint }}
<link rel="preload" href="{{ $styles.RelPermalink }}" as="style" integrity="{{ $styles.Data.Integrity }}" />
<link href="{{ $styles.RelPermalink }}" rel="stylesheet" integrity="{{ $styles.Data.Integrity }}" />
{{- else }}
<link href="{{ $styles.RelPermalink }}" rel="stylesheet" />
{{- end }}
{{- end }}
<!-- Custom CSS -->
{{- $custom := resources.Get "css/custom.css" }}
{{- if hugo.IsProduction -}}
{{- $custom = $custom | minify | fingerprint }}
<link href="{{ $custom.RelPermalink }}" rel="stylesheet" integrity="{{ $custom.Data.Integrity }}" />
{{- else }}
<link href="{{ $custom.RelPermalink }}" rel="stylesheet" />
{{- end }}

View File

@ -16,16 +16,41 @@
{{ end -}}
</title>
<meta name="description" content="{{ partial "utils/page-description.html" . }}" />
{{ partial "opengraph.html" . }}
{{ template "_internal/schema.html" . -}}
{{ template "_internal/twitter_cards.html" . -}}
{{ partialCached "head-css.html" . }}
<!-- Google Analytics -->
{{- if and .Site.GoogleAnalytics (eq hugo.Environment "production") }}
<link rel="preconnect" href="https://www.googletagmanager.com" crossorigin />
{{ partial "google-analytics.html" . }}
{{- end }}
<script>
/* Initialize light/dark mode */
if (localStorage.getItem("color-theme") === "dark" || (!("color-theme" in localStorage) && window.matchMedia("(prefers-color-scheme: dark)").matches)) {
const defaultTheme = '{{ site.Params.theme.default | default `system`}}';
const setDarkTheme = () => {
document.documentElement.classList.add("dark");
} else {
document.documentElement.style.colorScheme = "dark";
}
const setLightTheme = () => {
document.documentElement.classList.remove("dark");
document.documentElement.style.colorScheme = "light";
}
if ("color-theme" in localStorage) {
localStorage.getItem("color-theme") === "dark" ? setDarkTheme() : setLightTheme();
} else {
defaultTheme === "dark" ? setDarkTheme() : setLightTheme();
if (defaultTheme === "system") {
window.matchMedia("(prefers-color-scheme: dark)").matches ? setDarkTheme() : setLightTheme();
}
}
</script>

View File

@ -4,15 +4,23 @@
{{- $logoHeight := .Site.Params.navbar.logo.height | default "20" -}}
{{- $logoDarkPath := .Site.Params.navbar.logo.dark | default $logoPath -}}
{{- $navWidth := "max-w-[90rem]" -}}
{{- with .Site.Params.navbar.width -}}
{{ if eq . "normal" -}}
{{ $navWidth = "max-w-screen-xl" -}}
{{ else if eq . "full" -}}
{{ $navWidth = "max-w-full" -}}
{{ end -}}
{{- end -}}
<div class="sticky top-0 z-20 w-full bg-transparent print:hidden">
<div class="pointer-events-none absolute z-[-1] h-full w-full bg-white shadow-[0_2px_4px_rgba(0,0,0,.02),0_1px_0_rgba(0,0,0,.06)] contrast-more:shadow-[0_0_0_1px_#000] dark:bg-dark dark:shadow-[0_-1px_0_rgba(255,255,255,.1)_inset] contrast-more:dark:shadow-[0_0_0_1px_#fff]"></div>
<div class="nav-container sticky top-0 z-20 w-full bg-transparent print:hidden">
<div class="nav-container-blur pointer-events-none absolute z-[-1] h-full w-full bg-white dark:bg-dark shadow-[0_2px_4px_rgba(0,0,0,.02),0_1px_0_rgba(0,0,0,.06)] contrast-more:shadow-[0_0_0_1px_#000] dark:shadow-[0_-1px_0_rgba(255,255,255,.1)_inset] contrast-more:dark:shadow-[0_0_0_1px_#fff]"></div>
<nav class="mx-auto flex items-center justify-end gap-2 h-16 px-6 max-w-[90rem]">
<nav class="mx-auto flex items-center justify-end gap-2 h-16 px-6 {{ $navWidth }}">
<a class="flex items-center hover:opacity-75 ltr:mr-auto rtl:ml-auto" href="{{ $logoLink }}">
{{- if (.Site.Params.navbar.displayLogo | default true) }}
<img class="block dark:hidden" src="{{ $logoPath | relURL }}" alt="{{ .Site.Title }}" height="{{ $logoWidth }}" width="{{ $logoHeight }}" />
<img class="hidden dark:block" src="{{ $logoDarkPath | relURL }}" alt="{{ .Site.Title }}" height="{{ $logoWidth }}" width="{{ $logoHeight }}" />
<img class="block dark:hidden" src="{{ $logoPath | relURL }}" alt="{{ .Site.Title }}" height="{{ $logoHeight }}" width="{{ $logoWidth }}" />
<img class="hidden dark:block" src="{{ $logoDarkPath | relURL }}" alt="{{ .Site.Title }}" height="{{ $logoHeight }}" width="{{ $logoWidth }}" />
{{- end }}
{{- if (.Site.Params.navbar.displayTitle | default true) }}
<span class="mx-2 font-extrabold inline select-none" title="{{ .Site.Title }}">{{- .Site.Title -}}</span>
@ -22,7 +30,7 @@
{{- $currentPage := . -}}
{{- range .Site.Menus.main -}}
{{- if eq .Params.type "search" -}}
{{- partial "search.html" (dict "params" .Params) -}}
{{- partialCached "search.html" $currentPage -}}
{{- else -}}
{{- $external := strings.HasPrefix .URL "http" -}}
{{/* Display icon menu item */}}

View File

@ -1,68 +1,32 @@
{{- $jsTheme := resources.Get "js/theme.js" -}}
{{- $jsTheme := resources.Get "js/theme.js" | resources.ExecuteAsTemplate "theme.js" . -}}
{{- $jsMenu := resources.Get "js/menu.js" -}}
{{- $jsTabs := resources.Get "js/tabs.js" -}}
{{- $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" -}}
{{- $jsBackToTop := resources.Get "js/back-to-top.js" -}}
{{- $scripts := slice $jsTheme $jsMenu $jsCodeCopy $jsTabs $jsLang $jsFileTree $jsSidebar | resources.Concat "js/main.js" -}}
{{- $scripts := slice $jsTheme $jsMenu $jsCodeCopy $jsTabs $jsLang $jsFileTree $jsSidebar $jsBackToTop | resources.Concat "js/main.js" -}}
{{- if hugo.IsProduction -}}
{{- $scripts = $scripts | minify | fingerprint -}}
{{- end -}}
<script defer src="{{ $scripts.RelPermalink }}" integrity="{{ $scripts.Data.Integrity }}"></script>
{{/* FlexSearch */}}
{{/* Search */}}
{{- if (site.Params.search.enable | default true) -}}
{{- $jsSearchScript := printf "%s.search.js" .Language.Lang -}}
{{- $jsSearch := resources.Get "js/flexsearch.js" | resources.ExecuteAsTemplate $jsSearchScript . -}}
{{- if hugo.IsProduction -}}
{{- $jsSearch = $jsSearch | minify | fingerprint -}}
{{- $searchType := site.Params.search.type | default "flexsearch" -}}
{{- if eq $searchType "flexsearch" -}}
{{- $jsSearchScript := printf "%s.search.js" .Language.Lang -}}
{{- $jsSearch := resources.Get "js/flexsearch.js" | resources.ExecuteAsTemplate $jsSearchScript . -}}
{{- if hugo.IsProduction -}}
{{- $jsSearch = $jsSearch | minify | fingerprint -}}
{{- end -}}
{{- $flexSearchJS := resources.Get "lib/flexsearch/flexsearch.bundle.min.js" | fingerprint -}}
<script defer src="{{ $flexSearchJS.RelPermalink }}" integrity="{{ $flexSearchJS.Data.Integrity }}"></script>
<script defer src="{{ $jsSearch.RelPermalink }}" integrity="{{ $jsSearch.Data.Integrity }}"></script>
{{- else -}}
{{- errorf `search type "%s" is not supported` $searchType -}}
{{- end -}}
{{- $flexSearchJS := resources.Get "lib/flexsearch/flexsearch.bundle.min.js" | fingerprint -}}
<script defer src="{{ $flexSearchJS.RelPermalink }}" integrity="{{ $flexSearchJS.Data.Integrity }}"></script>
<script defer src="{{ $jsSearch.RelPermalink }}" integrity="{{ $jsSearch.Data.Integrity }}"></script>
{{- end -}}
{{/* Mermaid */}}
{{/* FIXME: need to investigate .Page.Store hasMermaid is set for homepage */}}
{{- if and (.Page.Store.Get "hasMermaid") (not .Page.IsHome) -}}
{{- $mermaidJS := resources.Get "lib/mermaid/mermaid.min.js" | fingerprint -}}
<script defer src="{{ $mermaidJS.RelPermalink }}" integrity="{{ $mermaidJS.Data.Integrity }}"></script>
<script>
document.addEventListener("DOMContentLoaded", function () {
const theme = document.documentElement.classList.contains("dark") ? "dark" : "default";
mermaid.initialize({ startOnLoad: true, theme: theme });
});
</script>
{{- end -}}
{{/* KaTex */}}
{{- if .Page.Params.math -}}
{{- $katexCSS := resources.Get "lib/katex/katex.min.css" | fingerprint -}}
{{- $katexJS := resources.Get "lib/katex/katex.min.js" | fingerprint -}}
{{- $mhchemJS := resources.Get "lib/katex/mhchem.min.js" | fingerprint -}}
{{- $katexAutoRenderJS := resources.Get "lib/katex/auto-render.min.js" | fingerprint -}}
<link type="text/css" rel="stylesheet" href="{{ $katexCSS.RelPermalink }}" integrity="{{ $katexCSS.Data.Integrity }}" />
<script defer src="{{ $katexJS.RelPermalink }}" integrity="{{ $katexJS.Data.Integrity }}"></script>
<script defer src="{{ $katexAutoRenderJS.RelPermalink }}" integrity="{{ $katexAutoRenderJS.Data.Integrity }}"></script>
<script defer src="{{ $mhchemJS.RelPermalink }}" integrity="{{ $mhchemJS.Data.Integrity }}"></script>
{{ $katexFonts := resources.Match "lib/katex/fonts/*" }}
{{- range $katexFonts -}}
{{ .Publish }}
{{- end -}}
<script>
// TODO: make render options configurable
document.addEventListener("DOMContentLoaded", function () {
renderMathInElement(document.body, {
delimiters: [
{ left: "$$", right: "$$", display: true },
{ left: "$", right: "$", display: false },
{ left: "\\(", right: "\\)", display: false },
{ left: "\\[", right: "\\]", display: true },
],
throwOnError: false,
});
});
</script>
{{ end }}

View File

@ -13,13 +13,13 @@
<kbd
class="absolute my-1.5 select-none ltr:right-1.5 rtl:left-1.5 h-5 rounded bg-white px-1.5 font-mono text-[10px] font-medium text-gray-500 border dark:border-gray-100/20 dark:bg-dark/50 contrast-more:border-current contrast-more:text-current contrast-more:dark:border-current items-center gap-1 transition-opacity pointer-events-none hidden sm:flex"
>
<span class="text-xs"></span>K
CTRL K
</kbd>
</div>
<div>
<ul
class="search-results hidden border border-gray-200 bg-white text-gray-100 dark:border-neutral-800 dark:bg-neutral-900 absolute top-full z-20 mt-2 overflow-auto overscroll-contain rounded-xl py-2.5 shadow-xl max-h-[min(calc(50vh-11rem-env(safe-area-inset-bottom)),400px)] md:max-h-[min(calc(100vh-5rem-env(safe-area-inset-bottom)),400px)] inset-x-0 ltr:md:left-auto rtl:md:right-auto contrast-more:border contrast-more:border-gray-900 contrast-more:dark:border-gray-50 w-screen min-h-[100px] max-w-[min(calc(100vw-2rem),calc(100%+20rem))]"
class="search-results hextra-scrollbar hidden border border-gray-200 bg-white text-gray-100 dark:border-neutral-800 dark:bg-neutral-900 absolute top-full z-20 mt-2 overflow-auto overscroll-contain rounded-xl py-2.5 shadow-xl max-h-[min(calc(50vh-11rem-env(safe-area-inset-bottom)),400px)] md:max-h-[min(calc(100vh-5rem-env(safe-area-inset-bottom)),400px)] inset-x-0 ltr:md:left-auto rtl:md:right-auto contrast-more:border contrast-more:border-gray-900 contrast-more:dark:border-gray-50 w-screen min-h-[100px] max-w-[min(calc(100vw-2rem),calc(100%+20rem))]"
style="transition: max-height 0.2s ease 0s;"
></ul>
</div>

View File

@ -6,134 +6,40 @@
{{- $sidebarClass := cond $disableSidebar (cond $displayPlaceholder "md:hidden xl:block" "md:hidden") "md:sticky" -}}
{{- $navRoot := cond (eq site.Home.Type "docs") site.Home $context.FirstSection -}}
{{- $navPages := union $navRoot.RegularPages $navRoot.Sections -}}
{{- $pageURL := $context.RelPermalink -}}
<aside class="sidebar-container flex flex-col print:hidden md:top-16 md:shrink-0 md:w-64 md:self-start max-md:[transform:translate3d(0,-100%,0)] {{ $sidebarClass }}">
<!-- Search bar on small screen -->
<div class="px-4 pt-4 md:hidden">
{{ partial "search.html" }}
</div>
<div class="overflow-y-auto overflow-x-hidden p-4 grow md:h-[calc(100vh-var(--navbar-height)-var(--menu-height))]">
{{/* Search bar on small screen */}}
{{- partialCached "sidebar/mobile-search" . -}}
<div class="hextra-scrollbar overflow-y-auto overflow-x-hidden p-4 grow md:h-[calc(100vh-var(--navbar-height)-var(--menu-height))]">
<ul class="flex flex-col gap-1 md:hidden">
<!-- Nav -->
{{ template "sidebar-main" (dict "context" site.Home "pageURL" $pageURL "page" $context "toc" true) -}}
{{ template "sidebar-footer" }}
{{/* Mobile Navigation */}}
{{ $treeMobile := partialCached "sidebar/section-tree" site.Home site.Home }}
{{ partial "sidebar/render-tree" (dict "context" site.Home "page" $context "tree" ($treeMobile | unmarshal)) }}
{{ partialCached "sidebar/extra" $context }}
</ul>
<!-- Sidebar on large screen -->
{{- if $disableSidebar -}}
{{- if $displayPlaceholder }}<div class="max-xl:hidden h-0 w-64 shrink-0"></div>{{ end -}}
{{ .context.Scratch.Set "enableFooterSwitches" true }}
{{- else -}}
<ul class="flex flex-col gap-1 max-md:hidden">
{{ template "sidebar-main" (dict "context" $navRoot "page" $context "pageURL" $pageURL) }}
{{ template "sidebar-footer" }}
</ul>
{{ end -}}
</div>
{{/* Hide theme switch when sidebar is disabled */}}
{{ $switchesClass := cond $disableSidebar "md:hidden" "" }}
<div class="{{ $switchesClass }} {{ with site.IsMultiLingual }}justify-end{{ end }} sticky bottom-0 bg-white dark:bg-dark mx-4 py-4 shadow-[0_-12px_16px_#fff] flex items-center gap-2 dark:border-neutral-800 dark:shadow-[0_-12px_16px_#111] contrast-more:border-neutral-400 contrast-more:shadow-none contrast-more:dark:shadow-none border-t" data-toggle-animation="show">
{{- with site.IsMultiLingual }}
{{ partial "language-switch" (dict "context" $context "grow" true) }}
{{ partial "theme-toggle" (dict "hideLabel" true) }}
{{ else }}
<div class="flex grow flex-col">
{{ partial "theme-toggle" }}
</div>
{{ end -}}
{{/* Sidebar on large screen */}}
<ul class="flex flex-col gap-1 max-md:hidden">
{{ $tree := partialCached "sidebar/section-tree" $navRoot $navRoot }}
{{ partial "sidebar/render-tree" (dict "context" $navRoot "page" $context "tree" ($tree | unmarshal)) }}
{{ partialCached "sidebar/extra" $context }}
</ul>
</div>
{{ partial "sidebar/switches" (dict "context" $context "disableSidebar" $disableSidebar) }}
</aside>
{{- define "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 -}}
{{- if eq $level 0 -}}
{{- range $items.ByWeight }}
{{- $active := eq $pageURL .RelPermalink -}}
{{- $shouldOpen := or (.Params.sidebar.open) (.IsAncestor $page) $active | default true }}
<li class="{{ if $shouldOpen }}open{{ end }}">
{{- template "sidebar-item-link" dict "context" . "active" $active "title" .LinkTitle "link" .RelPermalink -}}
{{- if and $toc $active -}}
{{- template "sidebar-toc" dict "page" . -}}
{{- end -}}
{{- template "sidebar-tree" dict "context" . "page" $page "pageURL" $pageURL "level" (add $level 1) "toc" $toc -}}
</li>
{{- end -}}
{{- else -}}
<div class="pt-1 ltr:pr-0 overflow-hidden transition-all ease-in-out duration-200">
<ul class='relative flex flex-col gap-1 before:absolute before:inset-y-1 before:w-px before:bg-gray-200 before:content-[""] ltr:ml-3 ltr:pl-3 ltr:before:left-0 rtl:mr-3 rtl:pr-3 rtl:before:right-0 dark:before:bg-neutral-800'>
{{- range $items.ByWeight }}
{{- $active := eq $pageURL .RelPermalink -}}
{{- $shouldOpen := or (.Params.sidebar.open) (.IsAncestor $page) $active | default true }}
{{- $title := .LinkTitle | default .File.BaseFileName -}}
<li class="flex flex-col gap-1 {{ if $shouldOpen }}open{{ end }}">
{{- template "sidebar-item-link" dict "context" . "active" $active "title" $title "link" .RelPermalink -}}
{{- if and $toc $active -}}
{{ template "sidebar-toc" dict "page" . }}
{{- end }}
{{ template "sidebar-tree" dict "context" . "page" $page "pageURL" $pageURL "level" (add $level 1) "toc" $toc }}
</li>
{{- end -}}
</ul>
</div>
{{- end -}}
{{- end }}
{{- end -}}
{{- define "sidebar-toc" -}}
{{ $page := .page }}
{{ with $page.Fragments.Headings }}
<ul class='flex flex-col gap-1 relative before:absolute before:inset-y-1 before:w-px before:bg-gray-200 before:content-[""] dark:before:bg-neutral-800 ltr:pl-3 ltr:before:left-0 rtl:pr-3 rtl:before:right-0 ltr:ml-3 rtl:mr-3'>
{{- range . }}
{{- with .Headings }}
{{- range . -}}
<li>
<a
href="#{{ anchorize .ID }}"
class="flex rounded px-2 py-1.5 text-sm transition-colors [word-break:break-word] cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:border flex gap-2 before:opacity-25 before:content-['#'] text-gray-500 hover:bg-gray-100 hover:text-gray-900 dark:text-neutral-400 dark:hover:bg-primary-100/5 dark:hover:text-gray-50 contrast-more:text-gray-900 contrast-more:dark:text-gray-50 contrast-more:border-transparent contrast-more:hover:border-gray-900 contrast-more:dark:hover:border-gray-50"
>
{{- .Title -}}
</a>
</li>
{{ end -}}
{{ end -}}
{{ end -}}
</ul>
{{ end }}
{{- end -}}
{{- define "sidebar-footer" -}}
{{- range site.Menus.sidebar -}}
{{- $name := or (T .Identifier) .Name -}}
{{ if eq .Params.type "separator" }}
<li class="[word-break:break-word] mt-5 mb-2 px-2 py-1.5 text-sm font-semibold text-gray-900 first:mt-0 dark:text-gray-100">
<span class="cursor-default">{{ $name }}</span>
</li>
{{ else }}
<li>{{ template "sidebar-item-link" dict "active" false "title" $name "link" (.URL | relLangURL) }}</li>
{{ end }}
{{- end -}}
{{- define "partials/sidebar/mobile-search" -}}
<div class="px-4 pt-4 md:hidden">
{{- partialCached "search.html" . -}}
</div>
{{- end -}}
{{- define "sidebar-item-link" -}}
{{- $external := strings.HasPrefix .link "http" -}}
{{- $open := .open | default true -}}
<a
class="flex items-center justify-between gap-2 cursor-pointer rounded px-2 py-1.5 text-sm transition-colors [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] [word-break:break-word]
{{- if .active }}
@ -144,21 +50,30 @@
href="{{ .link }}"
{{ if $external }}target="_blank" rel="noreferer"{{ end }}
>
{{- .title -}}
{{- .title | htmlUnescape | safeHTML -}}
{{- with .context }}
{{- if or .RegularPages .Sections }}
<span class="hextra-sidebar-collapsible-button">
{{- template "sidebear-collapsible-button" -}}
</span>
{{- end }}
{{- if or .RegularPages .Sections .section }}{{ partialCached "sidebar/collapsible-button" . }}{{ end -}}
{{ end -}}
</a>
{{- end -}}
{{- define "sidebar-separator" -}}
<div class="mt-4 border-t py-4 dark:border-neutral-800 contrast-more:border-neutral-400 dark:contrast-more:border-neutral-400" />
{{- end -}}
{{- define "partials/sidebar/switches" -}}
{{- $context := .context -}}
{{- $disableSidebar := .disableSidebar -}}
{{/* Hide theme switch when sidebar is disabled */}}
{{ $switchesClass := cond $disableSidebar "md:hidden" "" -}}
{{ $displayThemeToggle := (site.Params.theme.displayToggle | default true) -}}
{{- define "sidebear-collapsible-button" -}}
<svg fill="none" viewBox="0 0 24 24" stroke="currentColor" class="h-[18px] min-w-[18px] rounded-sm p-0.5 hover:bg-gray-800/5 dark:hover:bg-gray-100/5"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" class="origin-center transition-transform rtl:-rotate-180"></path></svg>
{{ if or site.IsMultiLingual $displayThemeToggle }}
<div class="{{ $switchesClass }} {{ with site.IsMultiLingual }}justify-end{{ end }} sticky bottom-0 bg-white dark:bg-dark mx-4 py-4 shadow-[0_-12px_16px_#fff] flex items-center gap-2 dark:border-neutral-800 dark:shadow-[0_-12px_16px_#111] contrast-more:border-neutral-400 contrast-more:shadow-none contrast-more:dark:shadow-none border-t" data-toggle-animation="show">
{{- with site.IsMultiLingual -}}
{{- partial "language-switch" (dict "context" $context "grow" true) -}}
{{- with $displayThemeToggle }}{{ partial "theme-toggle" (dict "hideLabel" true) }}{{ end -}}
{{- else -}}
{{- with $displayThemeToggle -}}
<div class="flex grow flex-col">{{ partial "theme-toggle" }}</div>
{{- end -}}
{{- end -}}
</div>
{{- end -}}
{{- end -}}

View File

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

View File

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

View File

@ -0,0 +1,15 @@
{{- $entry := . -}}
<div class="pt-1 ltr:pr-0 overflow-hidden transition-all ease-in-out duration-200">
<ul class='relative flex flex-col gap-1 before:absolute before:inset-y-1 before:w-px before:bg-gray-200 before:content-[""] ltr:ml-3 ltr:pl-3 ltr:before:left-0 rtl:mr-3 rtl:pr-3 rtl:before:right-0 dark:before:bg-neutral-800'>
{{- range $entry }}
{{- $shouldOpen := .open | default false }}
<li class="flex flex-col gap-1 {{ if $shouldOpen }}open{{ end }}">
{{- template "sidebar-item-link" (dict "context" . "active" false "title" .title "link" .link) -}}
{{- if .section -}}
{{- partial "sidebar/render-tree-branch-without-leaf" .section -}}
{{- end -}}
</li>
{{- end -}}
</ul>
</div>

View File

@ -0,0 +1,19 @@
{{- $context := .context -}}
{{- $page := .page -}}
{{- $entry := .entry -}}
{{- $pageLink := .page.RelPermalink -}}
<div class="pt-1 ltr:pr-0 overflow-hidden transition-all ease-in-out duration-200">
<ul class='relative flex flex-col gap-1 before:absolute before:inset-y-1 before:w-px before:bg-gray-200 before:content-[""] ltr:ml-3 ltr:pl-3 ltr:before:left-0 rtl:mr-3 rtl:pr-3 rtl:before:right-0 dark:before:bg-neutral-800'>
{{- range $entry }}
{{- $active := eq $pageLink .link -}}
{{- $shouldOpen := or (.open) (hasPrefix $pageLink .link) $active | default true }}
<li class="flex flex-col gap-1 {{ if $shouldOpen }}open{{ end }}">
{{- template "sidebar-item-link" (dict "context" . "active" $active "title" .title "link" .link) -}}
{{- if .section -}}
{{- partial "sidebar/render-tree-branch" (dict "context" $context "entry" .section "page" $page) -}}
{{- end -}}
</li>
{{- end -}}
</ul>
</div>

View File

@ -0,0 +1,18 @@
{{- $context := .context -}}
{{- $page := .page -}}
{{- $pageLink := .page.RelPermalink -}}
{{- range .tree -}}
{{- $active := eq $pageLink .link -}}
{{- $containsPage := hasPrefix $pageLink .link -}}
{{- $shouldOpen := or (.open) $containsPage $active | default false }}
<li class="{{ if $shouldOpen }}open{{ end }}">
{{- template "sidebar-item-link" (dict "context" . "active" $active "title" .title "link" .link) -}}
{{- if .section -}}
{{- if not $containsPage -}}
{{- partialCached "sidebar/render-tree-branch-without-leaf" .section .section -}}
{{- else -}}
{{- partial "sidebar/render-tree-branch" (dict "context" $context "entry" .section "page" $page) -}}
{{- end -}}
{{- end -}}
</li>
{{ end }}

View File

@ -0,0 +1,51 @@
{{ $context := . -}}
{{- $pages := union .RegularPages .Sections -}}
{{- $pages = where $pages "Params.sidebar.exclude" "!=" true -}}
{{- $data := slice -}}
{{- range $pages.ByWeight -}}
{{ $structure := (partial "sidebar/section-walk" .) | unmarshal -}}
{{ $data = $data | append $structure -}}
{{ end -}}
{{- define "partials/sidebar/section-walk" -}}
{{- with . -}}
{
"title": "{{ .LinkTitle | default .File.BaseFileName }}",
"link": "{{ .RelPermalink }}",
"toc": {{ partial "sidebar/section-page-toc" . }},
"open": {{ .Params.sidebar.open | default false }}
{{- if .IsSection }},
"section": [
{{ $pages := union .RegularPages .Sections -}}
{{ $pages = where $pages "Params.sidebar.exclude" "!=" true -}}
{{ range $index, $page := $pages.ByWeight -}}
{{ partial "sidebar/section-walk" . }}{{ if not (ge $index (sub (len $pages) 1)) }},{{ end -}}
{{ end -}}
]
{{ end -}}
}
{{- end }}
{{- end -}}
{{- define "partials/sidebar/section-page-toc" -}}
{{/* Get level 2 headings list used mainly for mobile navigation */}}
[
{{- with .Fragments.Headings -}}
{{/* Loop over level 1 headings */}}
{{- range . }}
{{- with .Headings }}
{{ $headings := . }}
{{- range $index, $heading := $headings }}
{{ $heading.Title | jsonify (dict "noHTMLEscape" true) }}
{{- if not (ge $index (sub (len $headings) 1)) }},{{ end -}}
{{ end -}}
{{- end -}}
{{ end -}}
{{- end -}}
]
{{- end -}}
{{ return ($data | jsonify (dict "noHTMLEscape" true)) }}

View File

@ -0,0 +1,21 @@
{{ $page := . }}
{{ with $page.Fragments.Headings }}
<ul
class='flex flex-col gap-1 relative before:absolute before:inset-y-1 before:w-px before:bg-gray-200 before:content-[""] dark:before:bg-neutral-800 ltr:pl-3 ltr:before:left-0 rtl:pr-3 rtl:before:right-0 ltr:ml-3 rtl:mr-3'
>
{{- range . }}
{{- with .Headings }}
{{- range . -}}
<li>
<a
href="#{{ anchorize .ID }}"
class="flex rounded px-2 py-1.5 text-sm transition-colors [word-break:break-word] cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:border gap-2 before:opacity-25 before:content-['#'] text-gray-500 hover:bg-gray-100 hover:text-gray-900 dark:text-neutral-400 dark:hover:bg-primary-100/5 dark:hover:text-gray-50 contrast-more:text-gray-900 contrast-more:dark:text-gray-50 contrast-more:border-transparent contrast-more:hover:border-gray-900 contrast-more:dark:hover:border-gray-50"
>
{{- .Title -}}
</a>
</li>
{{ end -}}
{{ end -}}
{{ end -}}
</ul>
{{ end }}

View File

@ -0,0 +1,42 @@
{{/* Mermaid */}}
{{/* FIXME: need to investigate .Page.Store hasMermaid is set for homepage */}}
{{- if and (.Page.Store.Get "hasMermaid") (not .Page.IsHome) -}}
{{- $mermaidJS := resources.Get "lib/mermaid/mermaid.min.js" | fingerprint -}}
<script defer src="{{ $mermaidJS.RelPermalink }}" integrity="{{ $mermaidJS.Data.Integrity }}"></script>
<script>
document.addEventListener("DOMContentLoaded", function () {
const theme = document.documentElement.classList.contains("dark") ? "dark" : "default";
mermaid.initialize({ startOnLoad: true, theme: theme });
});
</script>
{{- end -}}
{{/* KaTex */}}
{{- if .Page.Params.math -}}
{{- $katexCSS := resources.Get "lib/katex/katex.min.css" | fingerprint -}}
{{- $katexJS := resources.Get "lib/katex/katex.min.js" | fingerprint -}}
{{- $mhchemJS := resources.Get "lib/katex/mhchem.min.js" | fingerprint -}}
{{- $katexAutoRenderJS := resources.Get "lib/katex/auto-render.min.js" | fingerprint -}}
<link type="text/css" rel="stylesheet" href="{{ $katexCSS.RelPermalink }}" integrity="{{ $katexCSS.Data.Integrity }}" />
<script defer src="{{ $katexJS.RelPermalink }}" integrity="{{ $katexJS.Data.Integrity }}"></script>
<script defer src="{{ $katexAutoRenderJS.RelPermalink }}" integrity="{{ $katexAutoRenderJS.Data.Integrity }}"></script>
<script defer src="{{ $mhchemJS.RelPermalink }}" integrity="{{ $mhchemJS.Data.Integrity }}"></script>
{{ $katexFonts := resources.Match "lib/katex/fonts/*" }}
{{- range $katexFonts -}}
{{ .Publish }}
{{- end -}}
<script>
// TODO: make render options configurable
document.addEventListener("DOMContentLoaded", function () {
renderMathInElement(document.body, {
delimiters: [
{ left: "$$", right: "$$", display: true },
{ left: "$", right: "$", display: false },
{ left: "\\(", right: "\\)", display: false },
{ left: "\\[", right: "\\]", display: true },
],
throwOnError: false,
});
});
</script>
{{ end }}

View File

@ -3,10 +3,11 @@
{{- $toc := .Params.toc | default true -}}
{{- $onThisPage := (T "onThisPage") | default "On this page"}}
{{- $editThisPage := (T "editThisPage") | default "Edit this page"}}
{{- $backToTop := (T "backToTop") | default "Scroll to top" -}}
<nav class="hextra-toc order-last hidden w-64 shrink-0 xl:block print:hidden px-4" aria-label="table of contents">
{{- if $toc }}
<div class="sticky top-16 overflow-y-auto pr-4 pt-6 text-sm [hyphens:auto] max-h-[calc(100vh-var(--navbar-height)-env(safe-area-inset-bottom))] ltr:-mr-4 rtl:-ml-4">
<div class="hextra-scrollbar sticky top-16 overflow-y-auto pr-4 pt-6 text-sm [hyphens:auto] max-h-[calc(100vh-var(--navbar-height)-env(safe-area-inset-bottom))] ltr:-mr-4 rtl:-ml-4">
{{- with .Fragments.Headings -}}
<p class="mb-4 font-semibold tracking-tight">{{ $onThisPage }}</p>
{{- range . -}}
@ -25,10 +26,19 @@
<div class="{{ $borderClass }} sticky bottom-0 flex flex-col items-start gap-2 pb-8 dark:border-neutral-800 contrast-more:border-t contrast-more:border-neutral-400 contrast-more:shadow-none contrast-more:dark:border-neutral-400">
{{- if site.Params.editURL.enable -}}
{{- $editURL := site.Params.editURL.base | default "" -}}
{{- with .File -}}{{ $editURL = urls.JoinPath $editURL .Path }}{{- end -}}
{{- with .File -}}{{ $editURL = urls.JoinPath $editURL (replace .Path "\\" "/") }}{{- end -}}
{{- with .Params.editURL -}}{{ $editURL = .Params.editURL }}{{- end -}}
<a class="text-xs font-medium text-gray-500 hover:text-gray-900 dark:text-gray-400 dark:hover:text-gray-100 contrast-more:text-gray-800 contrast-more:dark:text-gray-50" href="{{ $editURL }}" target="_blank" rel="noreferer">{{ $editThisPage }}</a>
{{- end -}}
{{/* Scroll To Top */}}
<button aria-hidden="true" id="backToTop" onClick="scrollUp();" class="transition-all transition duration-75 opacity-0 text-xs font-medium text-gray-500 hover:text-gray-900 dark:text-gray-400 dark:hover:text-gray-100 contrast-more:text-gray-800 contrast-more:dark:text-gray-50">
<span>
{{- $backToTop -}}
</span>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="inline ml-1 h-3.5 w-3.5 border rounded-full border-gray-500 hover:border-gray-900 dark:border-gray-400 dark:hover:border-gray-100 contrast-more:border-gray-800 contrast-more:dark:border-gray-50">
<path stroke-linecap="round" stroke-linejoin="round" d="M4.5 15.75l7.5-7.5 7.5 7.5" />
</svg>
</button>
</div>
</div>
{{ end -}}
@ -49,7 +59,7 @@
{{- if .Title }}
<li class="my-2 scroll-my-6 scroll-py-6">
<a class="{{ $class }} inline-block text-gray-500 hover:text-gray-900 dark:text-gray-400 dark:hover:text-gray-300 contrast-more:text-gray-900 contrast-more:underline contrast-more:dark:text-gray-50 w-full break-words" href="#{{ anchorize .ID }}">
{{- .Title -}}
{{- .Title | safeHTML }}
</a>
</li>
{{- end -}}

View File

@ -1,5 +1,6 @@
{{/* Split page raw content into fragments */}}
{{ $page := . }}
{{ $page := .context }}
{{ $type := .type | default "content" }}
{{ $headingKeys := slice }}
{{ $headingTitles := slice }}
@ -22,24 +23,40 @@
{{ $len := len $headingKeys }}
{{ $data := dict }}
{{ if eq $len 0 }}
{{ $data = $data | merge (dict "" $page.Plain) }}
{{ else }}
{{ range seq $len }}
{{ $i := sub $len . }}
{{ $headingKey := index $headingKeys $i }}
{{ $headingTitle := index $headingTitles $i }}
{{ if eq $type "content" }}
{{/* Include full content of the page */}}
{{ if eq $len 0 }}
{{ $data = $data | merge (dict "" ($page.Plain | htmlUnescape | chomp)) }}
{{ else }}
{{/* Split the raw content from bottom to top */}}
{{ range seq $len }}
{{ $i := sub $len . }}
{{ $headingKey := index $headingKeys $i }}
{{ $headingTitle := index $headingTitles $i }}
{{ if eq $i 0 }}
{{ $data = $data | merge (dict $headingKey ($content | markdownify | plainify)) }}
{{ else }}
{{ $parts := split $content (printf "\n%s\n" $headingTitle) }}
{{ $lastPart := index $parts (sub (len $parts) 1) }}
{{ if eq $i 0 }}
{{ $data = $data | merge (dict $headingKey ($content | markdownify | plainify | htmlUnescape | chomp)) }}
{{ else }}
{{ $parts := split $content (printf "\n%s\n" $headingTitle) }}
{{ $lastPart := index $parts (sub (len $parts) 1) }}
{{ $data = $data | merge (dict $headingKey ($lastPart | markdownify | plainify)) }}
{{ $content = strings.TrimSuffix $lastPart $content }}
{{ $content = strings.TrimSuffix (printf "\n%s\n" $headingTitle) $content }}
{{ $data = $data | merge (dict $headingKey ($lastPart | markdownify | plainify | htmlUnescape | chomp)) }}
{{ $content = strings.TrimSuffix $lastPart $content }}
{{ $content = strings.TrimSuffix (printf "\n%s\n" $headingTitle) $content }}
{{ end }}
{{ end }}
{{ end }}
{{ else if (eq $type "heading" ) }}
{{/* Put heading keys with empty content to the data object */}}
{{ $data = dict "" "" }}
{{ range $headingKeys }}
{{ $data = $data | merge (dict . "") }}
{{ end }}
{{ else if (eq $type "title") }}
{{/* Use empty data object since title is included in search-data.json */}}
{{ $data = $data | merge (dict "" "") }}
{{ else if (eq $type "summary" ) }}
{{ $data = $data | merge (dict "" ($page.Summary | plainify | htmlUnescape | chomp)) }}
{{ end }}
{{ return $data }}

Some files were not shown because too many files have changed in this diff Show More