mirror of
				https://github.com/imfing/hextra.git
				synced 2025-10-31 15:44:51 -04:00 
			
		
		
		
	Compare commits
	
		
			75 Commits
		
	
	
		
			v0.2.3
			...
			122-improv
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 9fc253dff5 | ||
|   | 0125822785 | ||
|   | 1e1d1c8716 | ||
|   | 1048ee47d7 | ||
|   | 5842f893a3 | ||
|   | 78ce7c2f2e | ||
|   | 0652772c15 | ||
|   | 13e4eb3414 | ||
|   | 529fcd8a62 | ||
|   | 21a13c49f9 | ||
|   | 98d0a3dc73 | ||
|   | 24f3178ea8 | ||
|   | 230cc438b7 | ||
|   | 214cb7994f | ||
|   | 792ad4b569 | ||
|   | 97e6945c04 | ||
|   | 93cb788e52 | ||
|   | 88b0f1b2ab | ||
|   | a31b46f5e3 | ||
|   | 6641d36b98 | ||
|   | e42d01898a | ||
|   | 6cd4c55613 | ||
|   | cb09b7ce1e | ||
|   | 96c6ff073f | ||
|   | 28a20e1e7e | ||
|   | 5f4c7423d0 | ||
|   | 2bc4ed19e3 | ||
|   | 8aa6439132 | ||
|   | b7558aca44 | ||
|   | 55ff819dae | ||
|   | 924d8508d0 | ||
|   | 1b932f260a | ||
|   | 5768ed4695 | ||
|   | f4cea168b1 | ||
|   | e2d00fdcd0 | ||
|   | 103faa24f3 | ||
|   | d1bed05843 | ||
|   | 2df3c563bf | ||
|   | ec02eb34fe | ||
|   | 46dea718e6 | ||
|   | adf5a113fc | ||
|   | 6a19ac31c0 | ||
|   | 3c4ede96df | ||
|   | 01f7e3a425 | ||
|   | da5a087891 | ||
|   | 79883dc7cc | ||
|   | b283227046 | ||
|   | 0e9cf1a519 | ||
|   | fdc30c6cd5 | ||
|   | 3632294706 | ||
|   | 929578192b | ||
|   | c18d5def26 | ||
|   | 4e63aa4f14 | ||
|   | b51bfa3177 | ||
|   | c799160e86 | ||
|   | 00d26dee2c | ||
|   | e9ea9786e9 | ||
|   | 84ac7fe773 | ||
|   | a184cfd41e | ||
|   | 76ac694542 | ||
|   | f70ba59ca0 | ||
|   | 4a9a2850fc | ||
|   | 4553a8eda2 | ||
|   | 237d890f67 | ||
|   | 04e131f93a | ||
|   | 61e41f247b | ||
|   | 6d00cb32b0 | ||
|   | 939acc02a8 | ||
|   | e4c36236df | ||
|   | 4381f31085 | ||
|   | 171399889d | ||
|   | 3bcdf84ad4 | ||
|   | 8e8f7f23c9 | ||
|   | 5b71912ab2 | ||
|   | 34c6f6c7f3 | 
							
								
								
									
										110
									
								
								.github/CONTRIBUTING.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								.github/CONTRIBUTING.md
									
									
									
									
										vendored
									
									
										Normal 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 | ||||
|  | ||||
| We’re using [Discussions][discussions] as a place to connect with other members using Hextra: | ||||
|  | ||||
| - Ask questions you’re 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
									
								
							
							
						
						
									
										40
									
								
								.github/ISSUE_TEMPLATE/bug_report.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | ||||
| --- | ||||
| name: Bug report | ||||
| about: Create a report to help us improve | ||||
| title: '' | ||||
| labels: '' | ||||
| assignees: '' | ||||
|  | ||||
| --- | ||||
|  | ||||
| **Description** | ||||
|  | ||||
| <!-- Provide a clear and concise description of the bug --> | ||||
|  | ||||
| **Steps To Reproduce** | ||||
|  | ||||
| 1.  | ||||
| 2.  | ||||
| 3.  | ||||
|  | ||||
| **Expected Behavior** | ||||
|  | ||||
| <!-- What should have happened? --> | ||||
|  | ||||
| **Actual Behavior** | ||||
|  | ||||
| <!-- What happened instead? --> | ||||
|  | ||||
| **Screenshots** | ||||
|  | ||||
| <!-- If applicable, add screenshots to help explain your problem --> | ||||
|  | ||||
| **Environment** | ||||
|  | ||||
| - Hugo Version: [e.g., 0.85.0] | ||||
| - Browser/OS: [e.g., Chrome, MacOS] | ||||
| - Theme Version: [e.g., v2.0] | ||||
|  | ||||
| **Additional Context** | ||||
|  | ||||
| <!-- Add any other context about the problem here --> | ||||
							
								
								
									
										24
									
								
								.github/ISSUE_TEMPLATE/feature_request.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								.github/ISSUE_TEMPLATE/feature_request.md
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | ||||
| --- | ||||
| name: Feature request | ||||
| about: Suggest an idea for this project | ||||
| title: '' | ||||
| labels: '' | ||||
| assignees: '' | ||||
|  | ||||
| --- | ||||
|  | ||||
| **Feature Description** | ||||
|  | ||||
| <!-- Provide a clear and concise description of the feature --> | ||||
|  | ||||
| **Problem/Solution** | ||||
|  | ||||
| <!-- What problem will this feature solve? Or what new capability will it add? --> | ||||
|  | ||||
| **Alternatives Considered** | ||||
|  | ||||
| <!-- Have you considered any alternative solutions or workarounds? --> | ||||
|  | ||||
| **Additional Context** | ||||
|  | ||||
| <!-- Add any other context or screenshots about the feature request here --> | ||||
							
								
								
									
										6
									
								
								.github/workflows/pages.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								.github/workflows/pages.yml
									
									
									
									
										vendored
									
									
								
							| @@ -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: | ||||
|   | ||||
							
								
								
									
										3
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
								
							| @@ -1,4 +1,5 @@ | ||||
| { | ||||
|   "editor.tabSize": 2, | ||||
|   "css.customData": [".vscode/tailwind.json"] | ||||
|   "css.customData": [".vscode/tailwind.json"], | ||||
|   "markdown.extension.toc.levels": "2..6" | ||||
| } | ||||
|   | ||||
| @@ -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 | ||||
|  | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -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; | ||||
|   | ||||
							
								
								
									
										21
									
								
								assets/css/components/scrollbar.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								assets/css/components/scrollbar.css
									
									
									
									
									
										Normal 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; | ||||
|   } | ||||
| } | ||||
| @@ -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
									
								
							
							
						
						
									
										3
									
								
								assets/css/tailwind.css
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| @tailwind base; | ||||
| @tailwind components; | ||||
| @tailwind utilities; | ||||
| @@ -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
									
								
							
							
						
						
									
										22
									
								
								assets/js/back-to-top.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| // Back to top button | ||||
|  | ||||
| document.addEventListener("DOMContentLoaded", function () { | ||||
|   const backToTop = document.querySelector("#backToTop"); | ||||
|   if (backToTop) { | ||||
|     document.addEventListener("scroll", (e) => { | ||||
|       if (window.scrollY > 300) { | ||||
|         backToTop.classList.remove("opacity-0"); | ||||
|       } else { | ||||
|         backToTop.classList.add("opacity-0"); | ||||
|       } | ||||
|     }); | ||||
|   } | ||||
| }); | ||||
|  | ||||
| function scrollUp() { | ||||
|   window.scroll({ | ||||
|     top: 0, | ||||
|     left: 0, | ||||
|     behavior: "smooth", | ||||
|   }); | ||||
| } | ||||
| @@ -1,4 +1,36 @@ | ||||
| document.querySelectorAll('.code-copy-btn').forEach(function (button) { | ||||
| // 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'); | ||||
| @@ -27,4 +59,5 @@ document.querySelectorAll('.code-copy-btn').forEach(function (button) { | ||||
|         console.error('Target element not found'); | ||||
|       } | ||||
|     }); | ||||
|   }); | ||||
| }); | ||||
|   | ||||
| @@ -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 . }} | ||||
|   | ||||
| @@ -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 ( | ||||
|   // 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) | ||||
| ) { | ||||
|     (!("color-theme" in localStorage) && | ||||
|       ((window.matchMedia("(prefers-color-scheme: dark)").matches && defaultTheme === "system") || defaultTheme === "dark")) | ||||
|   ) { | ||||
|     themeToggleButtons.forEach((el) => el.dataset.theme = "dark"); | ||||
| } else { | ||||
|   } else { | ||||
|     themeToggleButtons.forEach((el) => el.dataset.theme = "light"); | ||||
| } | ||||
|   } | ||||
|  | ||||
| themeToggleButtons.forEach((el) => { | ||||
|   // 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") { | ||||
|         document.documentElement.classList.add("dark"); | ||||
|           setDarkTheme(); | ||||
|           localStorage.setItem("color-theme", "dark"); | ||||
|         } else { | ||||
|         document.documentElement.classList.remove("dark"); | ||||
|           setLightTheme(); | ||||
|           localStorage.setItem("color-theme", "light"); | ||||
|         } | ||||
|       } else { | ||||
|         if (document.documentElement.classList.contains("dark")) { | ||||
|         document.documentElement.classList.remove("dark"); | ||||
|           setLightTheme(); | ||||
|           localStorage.setItem("color-theme", "light"); | ||||
|         } else { | ||||
|         document.documentElement.classList.add("dark"); | ||||
|           setDarkTheme(); | ||||
|           localStorage.setItem("color-theme", "dark"); | ||||
|         } | ||||
|       } | ||||
|       el.dataset.theme = document.documentElement.classList.contains("dark") ? "dark" : "light"; | ||||
|     }); | ||||
| }); | ||||
|   }); | ||||
|  | ||||
|   // Listen for system theme changes | ||||
|   window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", (e) => { | ||||
|     if (defaultTheme === "system" && !("color-theme" in localStorage)) { | ||||
|       e.matches ? setDarkTheme() : setLightTheme(); | ||||
|       themeToggleButtons.forEach((el) => | ||||
|         el.dataset.theme = document.documentElement.classList.contains("dark") ? "dark" : "light" | ||||
|       ); | ||||
|     } | ||||
|   }); | ||||
| })(); | ||||
|   | ||||
| @@ -1,3 +1,10 @@ | ||||
| {{/* FlexSearch Index Data */}} | ||||
| {{- $indexType := site.Params.search.flexsearch.index | default "content" -}} | ||||
|  | ||||
| {{- if not (in (slice "content" "summary" "heading" "title" ) $indexType) -}} | ||||
|   {{- errorf "unknown flexsearch index type: %s" $indexType -}} | ||||
| {{- end -}} | ||||
|  | ||||
| {{- $pages := where .Site.Pages "Kind" "in" (slice "page" "section") -}} | ||||
| {{- $pages = where $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 -}} | ||||
|  | ||||
|   | ||||
							
								
								
									
										3
									
								
								dev.toml
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								dev.toml
									
									
									
									
									
								
							| @@ -18,6 +18,9 @@ | ||||
|     target = '$1' | ||||
|  | ||||
| [module] | ||||
|   [[module.mounts]] | ||||
|     source = "assets" | ||||
|     target = "assets" | ||||
|   [[module.mounts]] | ||||
|     source = "hugo_stats.json" | ||||
|     target = "assets/watching/hugo_stats.json" | ||||
|   | ||||
							
								
								
									
										
											BIN
										
									
								
								exampleSite/assets/images/space.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								exampleSite/assets/images/space.jpg
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 168 KiB | 
| @@ -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 <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 <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 >}} | ||||
|   | ||||
| @@ -12,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 >}} | ||||
|   | ||||
							
								
								
									
										39
									
								
								exampleSite/content/docs/advanced/comments.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								exampleSite/content/docs/advanced/comments.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | ||||
| --- | ||||
| title: Comments System | ||||
| linkTitle: Comments | ||||
| --- | ||||
|  | ||||
| Hextra supports adding comments system to your site. | ||||
| Currently [giscus](https://giscus.app/) is supported. | ||||
|  | ||||
| <!--more--> | ||||
|  | ||||
| ## giscus | ||||
|  | ||||
| [giscus](https://giscus.app/) is a comments system powered by [GitHub Discussions](https://docs.github.com/en/discussions). It is free and open source. | ||||
|  | ||||
| To enable giscus, you need to add the following to the site configuration file: | ||||
|  | ||||
| ```yaml {filename="hugo.yaml"} | ||||
| params: | ||||
|   comments: | ||||
|     enable: false | ||||
|     type: giscus | ||||
|  | ||||
|     giscus: | ||||
|       repo: <repository> | ||||
|       repoId: <repository ID> | ||||
|       category: <category> | ||||
|       categoryId: <category ID> | ||||
| ``` | ||||
|  | ||||
| The giscus configurations can be constructed from the [giscus.app](https://giscus.app/) website. More details can also be found there. | ||||
|  | ||||
| Comments can be enabled or disabled for a specific page in the page front matter: | ||||
|  | ||||
| ```yaml {filename="content/docs/about.md"} | ||||
| --- | ||||
| title: About | ||||
| comments: true | ||||
| --- | ||||
| ``` | ||||
| @@ -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%; | ||||
| } | ||||
| ``` | ||||
|  | ||||
|   | ||||
| @@ -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 | ||||
| @@ -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: | ||||
|   | ||||
| @@ -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 | ||||
| ``` | ||||
|   | ||||
| @@ -63,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"} | ||||
|  | ||||
| ``` | ||||
|  | ||||
| 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"} | ||||
|  | ||||
| ``` | ||||
|  | ||||
| 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"} | ||||
|  | ||||
| ``` | ||||
|  | ||||
| [page-bundles]: https://gohugo.io/content-management/page-bundles/#leaf-bundles | ||||
|   | ||||
| @@ -13,6 +13,7 @@ Hextra provides a collection of beautiful shortcodes to enhance your content. | ||||
| {{< cards >}} | ||||
|   {{< 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" >}} | ||||
|   | ||||
| @@ -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/). | ||||
|   | ||||
							
								
								
									
										43
									
								
								exampleSite/content/docs/guide/shortcodes/details.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								exampleSite/content/docs/guide/shortcodes/details.md
									
									
									
									
									
										Normal 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 */%}} | ||||
| ```` | ||||
| @@ -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 */%}} | ||||
| ``` | ||||
|   | ||||
| @@ -50,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 >}} | ||||
|   | ||||
							
								
								
									
										18
									
								
								exampleSite/content/showcase/index.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								exampleSite/content/showcase/index.md
									
									
									
									
									
										Normal 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 >}} | ||||
| @@ -7,6 +7,8 @@ enableGitInfo: true | ||||
| # enableEmoji: false | ||||
| hasCJKLanguage: true | ||||
|  | ||||
| # googleAnalytics: G-XXXXXXXXXX | ||||
|  | ||||
| outputs: | ||||
|   home: [HTML] | ||||
|   page: [HTML] | ||||
| @@ -24,13 +26,14 @@ languages: | ||||
|     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: | ||||
| @@ -51,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 | ||||
| @@ -93,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 | ||||
|   | ||||
| @@ -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", | ||||
|   | ||||
							
								
								
									
										
											BIN
										
									
								
								exampleSite/static/images/card-image-unprocessed.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								exampleSite/static/images/card-image-unprocessed.jpg
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 187 KiB | 
							
								
								
									
										10
									
								
								i18n/en.yaml
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								i18n/en.yaml
									
									
									
									
									
								
							| @@ -1,5 +1,9 @@ | ||||
| onThisPage: "On this page" | ||||
| backToTop: "Scroll to top" | ||||
| changeLanguage: "Change language" | ||||
| changeTheme: "Change theme" | ||||
| copyright: "© 2023 Hextra Project." | ||||
| editThisPage: "Edit this page on GitHub →" | ||||
| lastUpdated: "Last updated on" | ||||
|  | ||||
| copyright: "© 2023 Hextra Project." | ||||
| onThisPage: "On this page" | ||||
| readMore: "Read more →" | ||||
| searchPlaceholder: "Search..." | ||||
|   | ||||
							
								
								
									
										7
									
								
								i18n/es.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								i18n/es.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| onThisPage: "En esta página" | ||||
| editThisPage: "Edita esta página en GitHub →" | ||||
| lastUpdated: "Última actualización" | ||||
|  | ||||
| backToTop: "Subir al inicio" | ||||
|  | ||||
| copyright: "© 2023 Hextra Project." | ||||
							
								
								
									
										9
									
								
								i18n/ko.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								i18n/ko.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| backToTop: "맨위로 스크롤" | ||||
| changeLanguage: "언어변경" | ||||
| changeTheme: "테마변경" | ||||
| copyright: "© 2023 Hextra Project." | ||||
| editThisPage: "Github에서 편집하기 →" | ||||
| lastUpdated: "마지막 수정일자" | ||||
| onThisPage: "페이지 목차" | ||||
| readMore: "더보기 →" | ||||
| searchPlaceholder: "검색..." | ||||
							
								
								
									
										7
									
								
								i18n/pt.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								i18n/pt.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| onThisPage: "Nesta página" | ||||
| editThisPage: "Edita esta página no GitHub →" | ||||
| lastUpdated: "Última actualização" | ||||
|  | ||||
| backToTop: "Voltar ao topo" | ||||
|  | ||||
| copyright: "© 2023 Projecto Hextra." | ||||
							
								
								
									
										5
									
								
								i18n/sw.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								i18n/sw.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| onThisPage: "Kwenye ukurasa huu" | ||||
| editThisPage: "Hariri ukurasa huu kwenye GitHub →" | ||||
| lastUpdated: "Ilisasishwa mwisho" | ||||
| backToTop: "Tembeza hadi juu" | ||||
| copyright: "© 2023 Hextra Project." | ||||
							
								
								
									
										7
									
								
								i18n/vi.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								i18n/vi.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| onThisPage: "Ở trang này" | ||||
| editThisPage: "Sửa trang này trên GitHub →" | ||||
| lastUpdated: "Lần cuối cập nhật lúc" | ||||
|  | ||||
| backToTop: "Lướt lên đầu trang" | ||||
|  | ||||
| copyright: "© 2023 Hextra Project." | ||||
| @@ -12,4 +12,6 @@ onThisPage: "此页上" | ||||
| editThisPage: "在 GitHub 上编辑此页 →" | ||||
| lastUpdated: "最后更新于" | ||||
|  | ||||
| backToTop: "返回顶部" | ||||
|  | ||||
| copyright: "© 2023 Hextra Project." | ||||
|   | ||||
| @@ -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> | ||||
|   | ||||
| @@ -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 -}} | ||||
|   | ||||
| @@ -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> | ||||
|   | ||||
| @@ -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> | ||||
|   | ||||
							
								
								
									
										43
									
								
								layouts/_default/list.rss.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								layouts/_default/list.rss.xml
									
									
									
									
									
										Normal 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> | ||||
| @@ -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> | ||||
|   | ||||
							
								
								
									
										12
									
								
								layouts/_default/wide.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								layouts/_default/wide.html
									
									
									
									
									
										Normal 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 }} | ||||
| @@ -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> | ||||
|   | ||||
| @@ -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> | ||||
|   | ||||
| @@ -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> | ||||
|   | ||||
| @@ -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> | ||||
|   | ||||
| @@ -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 <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 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> | ||||
|       </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> | ||||
|   </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 -}} | ||||
|   | ||||
| @@ -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)]"> | ||||
|   | ||||
							
								
								
									
										11
									
								
								layouts/partials/components/comments.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								layouts/partials/components/comments.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| {{- $enableComments := site.Params.comments.enable | default false -}} | ||||
|  | ||||
| {{ if not (eq .Params.comments nil) }} | ||||
|   {{ $enableComments = .Params.comments }} | ||||
| {{ end }} | ||||
|  | ||||
| {{- if $enableComments -}} | ||||
|   {{- if eq site.Params.comments.type "giscus" -}} | ||||
|     {{ partial "components/giscus.html" . }} | ||||
|   {{- end -}} | ||||
| {{- end -}} | ||||
							
								
								
									
										62
									
								
								layouts/partials/components/giscus.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								layouts/partials/components/giscus.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,62 @@ | ||||
| {{- $lang := site.Language.LanguageCode | default `en` -}} | ||||
|  | ||||
| {{- with site.Params.comments.giscus -}} | ||||
| <script> | ||||
|   /* | ||||
|    * "preferred color scheme" theme in giscus works using "prefers-color-scheme" in media query. | ||||
|    * but, hugo's theme switch function works by using "color-theme" in local storage. | ||||
|    * This solution was created with reference to: | ||||
|    * https://github.com/giscus/giscus/issues/336#issuecomment-1214366281 | ||||
|   */ | ||||
|   function getGiscusTheme() { | ||||
|     return localStorage.getItem("color-theme"); | ||||
|   } | ||||
|  | ||||
|   function setGiscusTheme() { | ||||
|     function sendMessage(message) { | ||||
|       const iframe = document.querySelector('iframe.giscus-frame'); | ||||
|       if (!iframe) return; | ||||
|       iframe.contentWindow.postMessage({ giscus: message }, 'https://giscus.app'); | ||||
|     } | ||||
|     sendMessage({ | ||||
|       setConfig: { | ||||
|         theme: getGiscusTheme(), | ||||
|       }, | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   document.addEventListener('DOMContentLoaded', function () { | ||||
|     const giscusAttributes = { | ||||
|       "src": "https://giscus.app/client.js", | ||||
|       "data-repo": "{{ .repo }}", | ||||
|       "data-repo-id": "{{ .repoId }}", | ||||
|       "data-category": "{{ .category }}", | ||||
|       "data-category-id": "{{ .categoryId }}", | ||||
|       "data-mapping": "{{ .mapping | default `pathname` }}", | ||||
|       "data-strict": "{{ (string .strict) | default 0 }}", | ||||
|       "data-reactions-enabled": "{{ (string .reactionsEnabled) |  default 1 }}", | ||||
|       "data-emit-metadata": "{{ (string .emitMetadata) | default 0 }}", | ||||
|       "data-input-position": "{{ .inputPosition | default `top` }}", | ||||
|       "data-theme": getGiscusTheme(), | ||||
|       "data-lang": "{{ .lang | default $lang }}", | ||||
|       "crossorigin": "anonymous", | ||||
|       "async": "", | ||||
|     }; | ||||
|  | ||||
|     // Dynamically create script tag | ||||
|     const giscusScript = document.createElement("script"); | ||||
|     Object.entries(giscusAttributes).forEach(([key, value]) => giscusScript.setAttribute(key, value)); | ||||
|     document.getElementById('giscus').appendChild(giscusScript); | ||||
|  | ||||
|     // Update giscus theme when theme switcher is clicked | ||||
|     const toggles = document.querySelectorAll(".theme-toggle"); | ||||
|     if (toggles) { | ||||
|       toggles.forEach(toggle => toggle.addEventListener('click', setGiscusTheme)); | ||||
|     } | ||||
|   }); | ||||
| </script> | ||||
|  | ||||
| <div id="giscus"></div> | ||||
| {{- else -}} | ||||
|   {{ warnf "giscus is not configured" }} | ||||
| {{- end -}} | ||||
| @@ -5,16 +5,24 @@ | ||||
| {{- $prev := cond $reversePagination .PrevInSection .NextInSection -}} | ||||
| {{- $next := cond $reversePagination .NextInSection .PrevInSection -}} | ||||
|  | ||||
| {{- with .Params.prev -}} | ||||
| {{- 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 -}} | ||||
| {{- 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 -}} | ||||
|  | ||||
| {{- if or $prev $next -}} | ||||
|   | ||||
| @@ -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 -}} | ||||
|     {{- 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> | ||||
|   | ||||
							
								
								
									
										13
									
								
								layouts/partials/google-analytics.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								layouts/partials/google-analytics.html
									
									
									
									
									
										Normal 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 }} | ||||
| @@ -7,7 +7,7 @@ | ||||
|  | ||||
|   {{- if hugo.IsProduction }} | ||||
|     {{- $styles = $styles | minify | fingerprint }} | ||||
|     <link rel="preload" href="{{ $styles.RelPermalink }}" as="style" /> | ||||
|     <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" /> | ||||
|   | ||||
| @@ -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> | ||||
|  | ||||
|   | ||||
| @@ -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 */}} | ||||
|   | ||||
| @@ -1,19 +1,23 @@ | ||||
| {{- $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) -}} | ||||
|   {{- $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 -}} | ||||
| @@ -22,47 +26,7 @@ | ||||
|     {{- $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 }} | ||||
|   {{- else -}} | ||||
|     {{- errorf `search type "%s" is not supported` $searchType -}} | ||||
|   {{- 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 }} | ||||
| {{- end -}} | ||||
|   | ||||
| @@ -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> | ||||
|   | ||||
| @@ -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 -}} | ||||
|     {{/* Sidebar on large screen */}} | ||||
|     <ul class="flex flex-col gap-1 max-md:hidden"> | ||||
|         {{ template "sidebar-main" (dict "context" $navRoot "page" $context  "pageURL" $pageURL) }} | ||||
|         {{ template "sidebar-footer" }} | ||||
|       {{ $tree := partialCached "sidebar/section-tree" $navRoot $navRoot }} | ||||
|       {{ partial "sidebar/render-tree" (dict "context" $navRoot "page" $context "tree" ($tree | unmarshal)) }} | ||||
|       {{ partialCached "sidebar/extra" $context }} | ||||
|     </ul> | ||||
|     {{ end -}} | ||||
|   </div> | ||||
|   {{/* Hide theme switch when sidebar is disabled */}} | ||||
|   {{ $switchesClass := cond $disableSidebar "md:hidden" "" }} | ||||
|   <div class="{{ $switchesClass }} {{ with site.IsMultiLingual }}justify-end{{ end }} sticky bottom-0 bg-white dark:bg-dark mx-4 py-4 shadow-[0_-12px_16px_#fff] flex items-center gap-2 dark:border-neutral-800 dark:shadow-[0_-12px_16px_#111] contrast-more:border-neutral-400 contrast-more:shadow-none contrast-more:dark:shadow-none border-t" data-toggle-animation="show"> | ||||
|     {{- with site.IsMultiLingual }} | ||||
|       {{ partial "language-switch" (dict "context" $context "grow" true) }} | ||||
|       {{ partial "theme-toggle" (dict "hideLabel" true) }} | ||||
|     {{ else }} | ||||
|       <div class="flex grow flex-col"> | ||||
|         {{ partial "theme-toggle" }} | ||||
|       </div> | ||||
|     {{ end -}} | ||||
|   </div> | ||||
|  | ||||
|   {{ 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> | ||||
| {{- define "partials/sidebar/mobile-search" -}} | ||||
|   <div class="px-4 pt-4 md:hidden"> | ||||
|     {{- partialCached "search.html" . -}} | ||||
|   </div> | ||||
|     {{- end -}} | ||||
|   {{- end }} | ||||
| {{- end -}} | ||||
|  | ||||
| {{- define "sidebar-toc" -}} | ||||
|   {{ $page := .page }} | ||||
|   {{ with $page.Fragments.Headings }} | ||||
|     <ul class='flex flex-col gap-1 relative before:absolute before:inset-y-1 before:w-px before:bg-gray-200 before:content-[""] dark:before:bg-neutral-800 ltr:pl-3 ltr:before:left-0 rtl:pr-3 rtl:before:right-0 ltr:ml-3 rtl:mr-3'> | ||||
|       {{- range . }} | ||||
|         {{- with .Headings }} | ||||
|           {{- range . -}} | ||||
|             <li> | ||||
|               <a | ||||
|                 href="#{{ anchorize .ID }}" | ||||
|                 class="flex rounded px-2 py-1.5 text-sm transition-colors [word-break:break-word] cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:border flex gap-2 before:opacity-25 before:content-['#'] text-gray-500 hover:bg-gray-100 hover:text-gray-900 dark:text-neutral-400 dark:hover:bg-primary-100/5 dark:hover:text-gray-50 contrast-more:text-gray-900 contrast-more:dark:text-gray-50 contrast-more:border-transparent contrast-more:hover:border-gray-900 contrast-more:dark:hover:border-gray-50" | ||||
|               > | ||||
|                 {{- .Title -}} | ||||
|               </a> | ||||
|             </li> | ||||
|           {{ end -}} | ||||
|         {{ end -}} | ||||
|       {{ end -}} | ||||
|     </ul> | ||||
|   {{ end }} | ||||
| {{- end -}} | ||||
|  | ||||
| {{- define "sidebar-footer" -}} | ||||
|   {{- range site.Menus.sidebar -}} | ||||
|     {{- $name := or (T .Identifier) .Name -}} | ||||
|     {{ if eq .Params.type "separator" }} | ||||
|       <li class="[word-break:break-word] mt-5 mb-2 px-2 py-1.5 text-sm font-semibold text-gray-900 first:mt-0 dark:text-gray-100"> | ||||
|         <span class="cursor-default">{{ $name }}</span> | ||||
|       </li> | ||||
|     {{ else }} | ||||
|       <li>{{ template "sidebar-item-link" dict "active" false "title" $name "link" (.URL | relLangURL) }}</li> | ||||
|     {{ end }} | ||||
|   {{- end -}} | ||||
| {{- end -}} | ||||
|  | ||||
| {{- 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 -}} | ||||
|   | ||||
							
								
								
									
										3
									
								
								layouts/partials/sidebar/collapsible-button.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								layouts/partials/sidebar/collapsible-button.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| <span class="hextra-sidebar-collapsible-button"> | ||||
|   <svg fill="none" viewBox="0 0 24 24" stroke="currentColor" class="h-[18px] min-w-[18px] rounded-sm p-0.5 hover:bg-gray-800/5 dark:hover:bg-gray-100/5"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" class="origin-center transition-transform rtl:-rotate-180"></path></svg> | ||||
| </span> | ||||
							
								
								
									
										10
									
								
								layouts/partials/sidebar/extra.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								layouts/partials/sidebar/extra.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| {{- range site.Menus.sidebar -}} | ||||
|   {{- $name := or (T .Identifier) .Name -}} | ||||
|   {{ if eq .Params.type "separator" }} | ||||
|     <li class="[word-break:break-word] mt-5 mb-2 px-2 py-1.5 text-sm font-semibold text-gray-900 first:mt-0 dark:text-gray-100"> | ||||
|       <span class="cursor-default">{{ $name }}</span> | ||||
|     </li> | ||||
|   {{ else }} | ||||
|     <li>{{ template "sidebar-item-link" (dict "active" false "title" $name "link" (.URL | relLangURL)) }}</li> | ||||
|   {{ end }} | ||||
| {{- end -}} | ||||
| @@ -0,0 +1,15 @@ | ||||
| {{- $entry := . -}} | ||||
|  | ||||
| <div class="pt-1 ltr:pr-0 overflow-hidden transition-all ease-in-out duration-200"> | ||||
|   <ul class='relative flex flex-col gap-1 before:absolute before:inset-y-1 before:w-px before:bg-gray-200 before:content-[""] ltr:ml-3 ltr:pl-3 ltr:before:left-0 rtl:mr-3 rtl:pr-3 rtl:before:right-0 dark:before:bg-neutral-800'> | ||||
|     {{- range $entry }} | ||||
|       {{- $shouldOpen := .open | default false }} | ||||
|       <li class="flex flex-col gap-1 {{ if $shouldOpen }}open{{ end }}"> | ||||
|         {{- template "sidebar-item-link" (dict "context" . "active" false "title" .title "link" .link) -}} | ||||
|         {{- if .section -}} | ||||
|           {{- partial "sidebar/render-tree-branch-without-leaf" .section -}} | ||||
|         {{- end -}} | ||||
|       </li> | ||||
|     {{- end -}} | ||||
|   </ul> | ||||
| </div> | ||||
							
								
								
									
										19
									
								
								layouts/partials/sidebar/render-tree-branch.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								layouts/partials/sidebar/render-tree-branch.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| {{- $context := .context -}} | ||||
| {{- $page := .page -}} | ||||
| {{- $entry := .entry -}} | ||||
| {{- $pageLink := .page.RelPermalink -}} | ||||
|  | ||||
| <div class="pt-1 ltr:pr-0 overflow-hidden transition-all ease-in-out duration-200"> | ||||
|   <ul class='relative flex flex-col gap-1 before:absolute before:inset-y-1 before:w-px before:bg-gray-200 before:content-[""] ltr:ml-3 ltr:pl-3 ltr:before:left-0 rtl:mr-3 rtl:pr-3 rtl:before:right-0 dark:before:bg-neutral-800'> | ||||
|     {{- range $entry }} | ||||
|       {{- $active := eq $pageLink .link -}} | ||||
|       {{- $shouldOpen := or (.open) (hasPrefix $pageLink .link) $active | default true }} | ||||
|       <li class="flex flex-col gap-1 {{ if $shouldOpen }}open{{ end }}"> | ||||
|         {{- template "sidebar-item-link" (dict "context" . "active" $active "title" .title "link" .link) -}} | ||||
|         {{- if .section -}} | ||||
|           {{- partial "sidebar/render-tree-branch" (dict "context" $context "entry" .section "page" $page) -}} | ||||
|         {{- end -}} | ||||
|       </li> | ||||
|     {{- end -}} | ||||
|   </ul> | ||||
| </div> | ||||
							
								
								
									
										18
									
								
								layouts/partials/sidebar/render-tree.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								layouts/partials/sidebar/render-tree.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| {{- $context := .context -}} | ||||
| {{- $page := .page -}} | ||||
| {{- $pageLink := .page.RelPermalink -}} | ||||
| {{- range .tree -}} | ||||
|   {{- $active := eq $pageLink .link -}} | ||||
|   {{- $containsPage := hasPrefix $pageLink .link -}} | ||||
|   {{- $shouldOpen := or (.open) $containsPage $active | default false }} | ||||
|   <li class="{{ if $shouldOpen }}open{{ end }}"> | ||||
|     {{- template "sidebar-item-link" (dict "context" . "active" $active "title" .title "link" .link) -}} | ||||
|     {{- if .section -}} | ||||
|       {{- if not $containsPage -}} | ||||
|         {{- partialCached "sidebar/render-tree-branch-without-leaf" .section .section -}} | ||||
|       {{- else -}} | ||||
|         {{- partial "sidebar/render-tree-branch" (dict "context" $context "entry" .section "page" $page) -}} | ||||
|       {{- end -}} | ||||
|     {{- end -}} | ||||
|   </li> | ||||
| {{ end }} | ||||
							
								
								
									
										51
									
								
								layouts/partials/sidebar/section-tree.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								layouts/partials/sidebar/section-tree.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,51 @@ | ||||
| {{ $context := . -}} | ||||
|  | ||||
| {{- $pages := union .RegularPages .Sections -}} | ||||
| {{- $pages = where $pages "Params.sidebar.exclude" "!=" true -}} | ||||
|  | ||||
| {{- $data := slice -}} | ||||
|  | ||||
| {{- range $pages.ByWeight -}} | ||||
|   {{ $structure := (partial "sidebar/section-walk" .) | unmarshal -}} | ||||
|   {{ $data = $data | append $structure -}} | ||||
| {{ end -}} | ||||
|  | ||||
| {{- define "partials/sidebar/section-walk" -}} | ||||
|   {{- with . -}} | ||||
|   { | ||||
|     "title": "{{ .LinkTitle | default .File.BaseFileName }}", | ||||
|     "link": "{{ .RelPermalink }}", | ||||
|     "toc": {{ partial "sidebar/section-page-toc" . }}, | ||||
|     "open": {{ .Params.sidebar.open | default false }} | ||||
|     {{- if .IsSection }}, | ||||
|     "section": [ | ||||
|       {{ $pages := union .RegularPages .Sections -}} | ||||
|       {{ $pages = where $pages "Params.sidebar.exclude" "!=" true -}} | ||||
|       {{ range $index, $page := $pages.ByWeight -}} | ||||
|         {{ partial "sidebar/section-walk" . }}{{ if not (ge $index (sub (len $pages) 1)) }},{{ end -}} | ||||
|       {{ end -}} | ||||
|     ] | ||||
|     {{ end -}} | ||||
|   } | ||||
|   {{- end }} | ||||
| {{- end -}} | ||||
|  | ||||
| {{- define "partials/sidebar/section-page-toc" -}} | ||||
|   {{/* Get level 2 headings list used mainly for mobile navigation */}} | ||||
|   [ | ||||
|     {{- with .Fragments.Headings -}} | ||||
|       {{/* Loop over level 1 headings */}} | ||||
|       {{- range . }} | ||||
|         {{- with .Headings }} | ||||
|           {{ $headings := . }} | ||||
|           {{- range $index, $heading := $headings }} | ||||
|             {{ $heading.Title | jsonify (dict "noHTMLEscape" true) }} | ||||
|             {{- if not (ge $index (sub (len $headings) 1)) }},{{ end -}} | ||||
|           {{ end -}} | ||||
|         {{- end -}} | ||||
|       {{ end -}} | ||||
|     {{- end -}} | ||||
|   ] | ||||
| {{- end -}} | ||||
|  | ||||
| {{ return ($data | jsonify (dict "noHTMLEscape" true)) }} | ||||
							
								
								
									
										21
									
								
								layouts/partials/sidebar/toc.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								layouts/partials/sidebar/toc.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| {{ $page := . }} | ||||
| {{ with $page.Fragments.Headings }} | ||||
|   <ul | ||||
|     class='flex flex-col gap-1 relative before:absolute before:inset-y-1 before:w-px before:bg-gray-200 before:content-[""] dark:before:bg-neutral-800 ltr:pl-3 ltr:before:left-0 rtl:pr-3 rtl:before:right-0 ltr:ml-3 rtl:mr-3' | ||||
|   > | ||||
|     {{- range . }} | ||||
|       {{- with .Headings }} | ||||
|         {{- range . -}} | ||||
|           <li> | ||||
|             <a | ||||
|               href="#{{ anchorize .ID }}" | ||||
|               class="flex rounded px-2 py-1.5 text-sm transition-colors [word-break:break-word] cursor-pointer [-webkit-tap-highlight-color:transparent] [-webkit-touch-callout:none] contrast-more:border gap-2 before:opacity-25 before:content-['#'] text-gray-500 hover:bg-gray-100 hover:text-gray-900 dark:text-neutral-400 dark:hover:bg-primary-100/5 dark:hover:text-gray-50 contrast-more:text-gray-900 contrast-more:dark:text-gray-50 contrast-more:border-transparent contrast-more:hover:border-gray-900 contrast-more:dark:hover:border-gray-50" | ||||
|             > | ||||
|               {{- .Title -}} | ||||
|             </a> | ||||
|           </li> | ||||
|         {{ end -}} | ||||
|       {{ end -}} | ||||
|     {{ end -}} | ||||
|   </ul> | ||||
| {{ end }} | ||||
							
								
								
									
										42
									
								
								layouts/partials/third-party/scripts.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								layouts/partials/third-party/scripts.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | ||||
| {{/* Mermaid */}} | ||||
| {{/* FIXME: need to investigate .Page.Store hasMermaid is set for homepage */}} | ||||
| {{- if and (.Page.Store.Get "hasMermaid") (not .Page.IsHome) -}} | ||||
|   {{- $mermaidJS := resources.Get "lib/mermaid/mermaid.min.js" | fingerprint -}} | ||||
|   <script defer src="{{ $mermaidJS.RelPermalink }}" integrity="{{ $mermaidJS.Data.Integrity }}"></script> | ||||
|   <script> | ||||
|     document.addEventListener("DOMContentLoaded", function () { | ||||
|       const theme = document.documentElement.classList.contains("dark") ? "dark" : "default"; | ||||
|       mermaid.initialize({ startOnLoad: true, theme: theme }); | ||||
|     }); | ||||
|   </script> | ||||
| {{- end -}} | ||||
|  | ||||
| {{/* KaTex */}} | ||||
| {{- if .Page.Params.math -}} | ||||
|   {{- $katexCSS := resources.Get "lib/katex/katex.min.css" | fingerprint -}} | ||||
|   {{- $katexJS := resources.Get "lib/katex/katex.min.js" | fingerprint -}} | ||||
|   {{- $mhchemJS := resources.Get "lib/katex/mhchem.min.js" | fingerprint -}} | ||||
|   {{- $katexAutoRenderJS := resources.Get "lib/katex/auto-render.min.js" | fingerprint -}} | ||||
|   <link type="text/css" rel="stylesheet" href="{{ $katexCSS.RelPermalink }}" integrity="{{ $katexCSS.Data.Integrity }}" /> | ||||
|   <script defer src="{{ $katexJS.RelPermalink }}" integrity="{{ $katexJS.Data.Integrity }}"></script> | ||||
|   <script defer src="{{ $katexAutoRenderJS.RelPermalink }}" integrity="{{ $katexAutoRenderJS.Data.Integrity }}"></script> | ||||
|   <script defer src="{{ $mhchemJS.RelPermalink }}" integrity="{{ $mhchemJS.Data.Integrity }}"></script> | ||||
|   {{ $katexFonts := resources.Match "lib/katex/fonts/*" }} | ||||
|   {{- range $katexFonts -}} | ||||
|     {{ .Publish }} | ||||
|   {{- end -}} | ||||
|   <script> | ||||
|     // TODO: make render options configurable | ||||
|     document.addEventListener("DOMContentLoaded", function () { | ||||
|       renderMathInElement(document.body, { | ||||
|         delimiters: [ | ||||
|           { left: "$$", right: "$$", display: true }, | ||||
|           { left: "$", right: "$", display: false }, | ||||
|           { left: "\\(", right: "\\)", display: false }, | ||||
|           { left: "\\[", right: "\\]", display: true }, | ||||
|         ], | ||||
|         throwOnError: false, | ||||
|       }); | ||||
|     }); | ||||
|   </script> | ||||
| {{ end }} | ||||
| @@ -3,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 -}} | ||||
|   | ||||
| @@ -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 }} | ||||
| {{ 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)) }} | ||||
|         {{ $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)) }} | ||||
|         {{ $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 }} | ||||
|   | ||||
| @@ -1,11 +1,11 @@ | ||||
| {{ with .Description | plainify -}} | ||||
| {{ with .Description | plainify | htmlUnescape -}} | ||||
|   {{ . -}} | ||||
| {{ else -}} | ||||
|   {{ if .IsHome -}} | ||||
|     {{ with .Site.Params.description | plainify -}} | ||||
|     {{ with .Site.Params.description | plainify | htmlUnescape -}} | ||||
|       {{ . -}} | ||||
|     {{ end -}} | ||||
|   {{ else -}} | ||||
|     {{ .Summary | plainify | chomp -}} | ||||
|     {{ .Summary | plainify | htmlUnescape | chomp -}} | ||||
|   {{ end -}} | ||||
| {{ end -}} | ||||
|   | ||||
							
								
								
									
										27
									
								
								layouts/partials/utils/page-width.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								layouts/partials/utils/page-width.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | ||||
| {{/* Get page width from site configuration */}} | ||||
|  | ||||
| {{/* Default page width */}} | ||||
| {{- $pageWidth := "" -}} | ||||
|  | ||||
| {{/* Get page width setting from page front matter or site params */}} | ||||
| {{ with .Params.width -}} | ||||
|   {{ $pageWidth = . -}} | ||||
| {{ else -}} | ||||
|   {{ with .Site.Params.page.width -}} | ||||
|     {{ $pageWidth = . -}} | ||||
|   {{ end -}} | ||||
| {{ end -}} | ||||
|  | ||||
| {{- with $pageWidth -}} | ||||
|   {{ if eq . "wide" -}} | ||||
|     {{ $pageWidth = "max-w-[90rem]" -}} | ||||
|   {{ else if eq . "full" -}} | ||||
|     {{ $pageWidth = "max-w-full" -}} | ||||
|   {{ else -}} | ||||
|     {{ $pageWidth = "max-w-screen-xl" -}} | ||||
|   {{ end -}} | ||||
| {{ else -}} | ||||
|   {{ $pageWidth = "max-w-screen-xl" -}} | ||||
| {{ end -}} | ||||
|  | ||||
| {{ return $pageWidth }} | ||||
| @@ -1,40 +0,0 @@ | ||||
| {{- $pctx := . -}} | ||||
| {{- if .IsHome -}}{{ $pctx = .Site }}{{- end -}} | ||||
| {{- $pages := slice -}} | ||||
| {{- if or $.IsHome $.IsSection -}} | ||||
| {{- $pages = $pctx.RegularPages -}} | ||||
| {{- else -}} | ||||
| {{- $pages = $pctx.Pages -}} | ||||
| {{- end -}} | ||||
| {{- $limit := .Site.Config.Services.RSS.Limit -}} | ||||
| {{- if ge $limit 1 -}} | ||||
| {{- $pages = $pages | first $limit -}} | ||||
| {{- end -}} | ||||
| {{- printf "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>" | safeHTML }} | ||||
| <rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"> | ||||
|   <channel> | ||||
|     <title>{{ if eq  .Title  .Site.Title }}{{ .Site.Title }}{{ else }}{{ with .Title }}{{.}} of {{ end }}{{ .Site.Title }}{{ end }}</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> | ||||
|     <language>{{ site.Language.LanguageCode }}</language>{{ 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 -}} | ||||
|     {{ range $pages }} | ||||
|     <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>{{ with .Description | html }}{{ . }}{{ else }}{{ .Summary | html }}{{ end -}}</description> | ||||
|       <content:encoded>{{ (printf "<![CDATA[%s]]>" .Content) | safeHTML }}</content:encoded> | ||||
|     </item> | ||||
|     {{ end }} | ||||
|   </channel> | ||||
| </rss> | ||||
| @@ -17,8 +17,8 @@ | ||||
| <div class="overflow-x-auto mt-6 flex rounded-lg border py-2 ltr:pr-4 rtl:pl-4 contrast-more:border-current contrast-more:dark:border-current {{ $class }}"> | ||||
|   <div class="select-none text-xl ltr:pl-3 ltr:pr-2 rtl:pr-3 rtl:pl-2" style='font-family: "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";'>{{ $emoji }}</div> | ||||
|   <div class="w-full min-w-0 leading-7"> | ||||
|     <p class="mt-6 leading-7 first:mt-0"> | ||||
|     <div class="mt-6 leading-7 first:mt-0"> | ||||
|       {{ .Inner | markdownify }} | ||||
|     </p> | ||||
|     </div> | ||||
|   </div> | ||||
| </div> | ||||
|   | ||||
| @@ -1,9 +1,42 @@ | ||||
| {{- $context := . -}} | ||||
| {{- $link := .Get "link" -}} | ||||
| {{- $title := .Get "title" -}} | ||||
| {{- $icon := .Get "icon" -}} | ||||
| {{- $subtitle := .Get "subtitle" }} | ||||
| {{- $image := .Get "image" }} | ||||
| {{- $context := . -}} | ||||
| {{- $subtitle := .Get "subtitle" -}} | ||||
| {{- $image := .Get "image" -}} | ||||
| {{- $width := 0 -}} | ||||
| {{- $height := 0 -}} | ||||
| {{- $imageStyle := .Get "imageStyle" -}} | ||||
|  | ||||
| {{/* Image processing options */}} | ||||
| {{- $method := .Get "method" | default "Resize" | humanize -}} | ||||
| {{- $options := .Get "options" | default "800x webp q80" -}} | ||||
|  | ||||
| {{- if and $image (not (urls.Parse $image).Scheme) -}} | ||||
|   {{/* Process images in assets */}} | ||||
|   {{- with resources.Get $image -}} | ||||
|     {{- $processed := "" -}} | ||||
|     {{- if eq $method "Resize" -}} | ||||
|       {{- $processed = (.Resize $options) -}} | ||||
|     {{- else if eq $method "Fit" -}} | ||||
|       {{- $processed = (.Fit $options) -}} | ||||
|     {{- else if eq $method "Fill" -}} | ||||
|       {{- $processed = (.Fill $options) -}} | ||||
|     {{- else if eq $method "Crop" -}} | ||||
|       {{- $processed = (.Crop $options) -}} | ||||
|     {{- else -}} | ||||
|       {{- errorf "Invalid image processing command: Must be one of Crop, Fit, Fill or Resize." -}} | ||||
|     {{- end -}} | ||||
|     {{- $width = $processed.Width -}} | ||||
|     {{- $height = $processed.Height -}} | ||||
|     {{- $image = $processed.RelPermalink -}} | ||||
|   {{- else -}} | ||||
|     {{/* Otherwise, use relative link of the image */}} | ||||
|     {{- if hasPrefix $image "/" -}} | ||||
|       {{- $image = relURL (strings.TrimPrefix "/" $image) -}} | ||||
|     {{- end -}} | ||||
|   {{- end -}} | ||||
| {{- end -}} | ||||
|  | ||||
| {{ $linkClass := "hover:border-gray-300 bg-transparent shadow-sm dark:border-neutral-800 hover:bg-slate-50 hover:shadow-md dark:hover:border-neutral-700 dark:hover:bg-neutral-900" }} | ||||
| {{- with $image -}} | ||||
| @@ -11,29 +44,39 @@ | ||||
| {{- end -}} | ||||
|  | ||||
| {{- $external := strings.HasPrefix $link "http" -}} | ||||
| {{- $href := cond (strings.HasPrefix $link "/") ($link | relURL) $link -}} | ||||
|  | ||||
|  | ||||
| <a | ||||
|   class="hextra-card group flex flex-col justify-start overflow-hidden rounded-lg border border-gray-200 text-current no-underline dark:shadow-none hover:shadow-gray-100 dark:hover:shadow-none shadow-gray-100 active:shadow-sm active:shadow-gray-200 transition-all duration-200 {{ $linkClass }}" | ||||
|   href="{{ $link }}" | ||||
|   {{- if $external -}} | ||||
|     target="_blank" | ||||
|     rel="noreferrer" | ||||
|   href="{{ $href }}" | ||||
|   {{- if $external }} | ||||
|     target="_blank" rel="noreferrer" | ||||
|   {{- end -}} | ||||
| > | ||||
|   {{- with $image -}} | ||||
|     <img alt="{{ $title }}" loading="lazy" decoding="async" style="color: transparent;" src="{{ $image }}" /> | ||||
|     <img | ||||
|       alt="{{ $title }}" | ||||
|       loading="lazy" | ||||
|       decoding="async" | ||||
|       src="{{ $image | safeURL }}" | ||||
|       {{ with $width }}width="{{ . }}"{{ end }} | ||||
|       {{ with $height }}height="{{ . }}"{{ end }} | ||||
|       {{ with $imageStyle }}style="{{ . | safeCSS }}"{{ end }} | ||||
|     /> | ||||
|   {{- end -}} | ||||
|  | ||||
|   {{ $padding := "p-4"}} | ||||
|   {{- $padding := "p-4" -}} | ||||
|   {{- with $subtitle -}} | ||||
|     {{ $padding = "pt-4 px-4"}} | ||||
|     {{- $padding = "pt-4 px-4" -}} | ||||
|   {{- end -}} | ||||
|  | ||||
|  | ||||
|   <span class="flex font-semibold items-start gap-2 {{ $padding }} text-gray-700 hover:text-gray-900 dark:text-neutral-200 dark:hover:text-neutral-50"> | ||||
|     {{- with $icon }}{{ partial "utils/icon.html" (dict "name" $icon) -}}{{ end -}} | ||||
|     {{- with $icon }}{{ partial "utils/icon.html" (dict "name" $icon) -}}{{- end -}} | ||||
|     {{- $title -}} | ||||
|   </span> | ||||
|   {{- with $subtitle -}} | ||||
|     <div class="line-clamp-3 text-sm font-normal text-gray-500 dark:text-gray-400 px-4 mb-4 mt-2">{{ $subtitle }}</div> | ||||
|     <div class="line-clamp-3 text-sm font-normal text-gray-500 dark:text-gray-400 px-4 mb-4 mt-2">{{- $subtitle | markdownify -}}</div> | ||||
|   {{- end -}} | ||||
| </a> | ||||
|   | ||||
| @@ -1,8 +1,8 @@ | ||||
| {{- $title := .Get "title" | default "" -}} | ||||
| {{- $closed := eq (.Get "closed") "true" | default false -}} | ||||
|  | ||||
| <details class="last-of-type:mb-0 rounded-lg bg-neutral-50 dark:bg-neutral-800 p-2 mt-4" data-expanded="true" {{ if not $closed }}open{{ end }}> | ||||
|   <summary class="flex items-center cursor-pointer select-none list-none p-1 transition-colors hover:bg-gray-100 dark:hover:bg-neutral-800 before:mr-1 before:inline-block before:transition-transform before:content-[''] dark:before:invert rtl:before:rotate-180 [[data-expanded]>&]:before:rotate-90"> | ||||
| <details class="last-of-type:mb-0 rounded-lg bg-neutral-50 dark:bg-neutral-800 p-2 mt-4 group" {{ if not $closed }}open{{ end }}> | ||||
|   <summary class="flex items-center cursor-pointer select-none list-none p-1 rounded transition-colors hover:bg-gray-100 dark:hover:bg-neutral-800 before:mr-1 before:inline-block before:transition-transform before:content-[''] dark:before:invert rtl:before:rotate-180 group-open:before:rotate-90"> | ||||
|     <strong class="text-lg">{{ $title | markdownify }}</strong> | ||||
|   </summary> | ||||
|   <div class="p-2 overflow-hidden"> | ||||
|   | ||||
							
								
								
									
										28
									
								
								layouts/shortcodes/hextra/feature-card.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								layouts/shortcodes/hextra/feature-card.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | ||||
| {{- $title := .Get "title" -}} | ||||
| {{- $subtitle := .Get "subtitle" -}} | ||||
| {{- $class := .Get "class" -}} | ||||
| {{- $image := .Get "image" -}} | ||||
| {{- $imageClass := .Get "imageClass" -}} | ||||
| {{- $style := .Get "style" -}} | ||||
| {{- $icon := .Get "icon" -}} | ||||
|  | ||||
|  | ||||
| <div | ||||
|   {{ with $style }}style="{{ . | safeCSS }}"{{ end }} | ||||
|   class="{{ $class }} hextra-feature-card relative overflow-hidden rounded-3xl border border-gray-200 hover:border-gray-300 dark:border-neutral-800 dark:hover:border-neutral-700 before:pointer-events-none before:absolute before:inset-0 before:bg-glass-gradient" | ||||
| > | ||||
|   <div class="relative w-full p-6"> | ||||
|     <h3 class="text-2xl font-medium leading-6 mb-2 flex items-center"> | ||||
|       {{ with $icon -}} | ||||
|         <span class="pr-2"> | ||||
|           {{- partial "utils/icon.html" (dict "name" . "attributes" "height=1.5rem") -}} | ||||
|         </span> | ||||
|       {{ end -}} | ||||
|       <span>{{ $title }}</span> | ||||
|     </h3> | ||||
|     <p class="text-gray-500 dark:text-gray-400 text-sm leading-6">{{ $subtitle | markdownify }}</p> | ||||
|   </div> | ||||
|   {{- with $image -}} | ||||
|     <img src="{{ . }}" class="absolute max-w-none {{ $imageClass }}" alt="{{ $title }}" /> | ||||
|   {{- end -}} | ||||
| </div> | ||||
							
								
								
									
										9
									
								
								layouts/shortcodes/hextra/feature-grid.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								layouts/shortcodes/hextra/feature-grid.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| {{- $style := .Get "style" -}} | ||||
|  | ||||
|  | ||||
| <div | ||||
|   class="grid sm:grid-cols-2 lg:grid-cols-3 grid-cols-1 gap-4 w-full" | ||||
|   {{ with $style }}style="{{ . | safeCSS }}"{{ end }} | ||||
| > | ||||
|   {{ .Inner }} | ||||
| </div> | ||||
							
								
								
									
										15
									
								
								layouts/shortcodes/hextra/hero-badge.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								layouts/shortcodes/hextra/hero-badge.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| {{- $link := .Get "link" -}} | ||||
| {{- $external := hasPrefix $link "http" -}} | ||||
| {{- $href := cond (hasPrefix $link "/") ($link | relURL) $link -}} | ||||
| {{- $class := .Get "class" }} | ||||
| {{- $style := .Get "style" -}} | ||||
|  | ||||
|  | ||||
| <a | ||||
|   href="{{ $href }}" | ||||
|   class="{{ $class }} inline-flex items-center rounded-full gap-2 px-3 py-1 text-xs text-gray-600 dark:text-gray-400 bg-gray-100 dark:bg-neutral-800 dark:border-neutral-800 border hover:border-gray-400 dark:hover:text-gray-50 dark:hover:border-gray-600 transition-all ease-in duration-200" | ||||
|   {{ with $style }}style="{{ . | safeCSS }}"{{ end }} | ||||
|   {{ if $external }}target="_blank" rel="noreferrer"{{ end -}} | ||||
| > | ||||
|   {{ .Inner | markdownify }} | ||||
| </a> | ||||
							
								
								
									
										15
									
								
								layouts/shortcodes/hextra/hero-button.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								layouts/shortcodes/hextra/hero-button.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| {{- $link := .Get "link" -}} | ||||
| {{- $text := .Get "text" -}} | ||||
| {{- $style := .Get "style" -}} | ||||
|  | ||||
| {{- $external := hasPrefix $link "http" -}} | ||||
| {{- $href := cond (hasPrefix $link "/") ($link | relURL) $link -}} | ||||
|  | ||||
| <a | ||||
|   href="{{ $href }}" | ||||
|   class="font-medium cursor-pointer px-6 py-3 rounded-full text-center text-white inline-block bg-primary-600 hover:bg-primary-700 focus:outline-none focus:ring-4 focus:ring-primary-300 dark:bg-primary-600 dark:hover:bg-primary-700 dark:focus:ring-primary-800 transition-all ease-in duration-200" | ||||
|   {{ with $style }}style="{{ . | safeCSS }}"{{ end }} | ||||
|   {{ if $external }}target="_blank" rel="noreferrer"{{ end -}} | ||||
| > | ||||
|   {{- $text -}} | ||||
| </a> | ||||
							
								
								
									
										9
									
								
								layouts/shortcodes/hextra/hero-headline.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								layouts/shortcodes/hextra/hero-headline.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| {{- $style := .Get "style" -}} | ||||
|  | ||||
|  | ||||
| <h1 | ||||
|   class="text-4xl font-bold leading-none tracking-tighter md:text-5xl py-2 bg-clip-text text-transparent bg-gradient-to-r from-gray-900 to-gray-600 dark:from-gray-100 dark:to-gray-400" | ||||
|   {{ with $style }}style="{{ . | safeCSS }}"{{ end }} | ||||
| > | ||||
|   {{ .Inner | markdownify }} | ||||
| </h1> | ||||
							
								
								
									
										9
									
								
								layouts/shortcodes/hextra/hero-subtitle.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								layouts/shortcodes/hextra/hero-subtitle.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| {{- $style := .Get "style" -}} | ||||
|  | ||||
|  | ||||
| <p | ||||
|   class="text-xl text-gray-600 dark:text-gray-400 sm:text-xl" | ||||
|   {{ with $style }}style="{{ . | safeCSS }}"{{ end }} | ||||
| > | ||||
|   {{ .Inner | markdownify }} | ||||
| </p> | ||||
| @@ -1,9 +1,9 @@ | ||||
| {{- $name := .Get "name" | default (.Get 0) -}} | ||||
| {{- $icon := index site.Data.icons (.Get 0) -}} | ||||
| {{- $attributes := "height=1em"}} | ||||
| {{- $icon := index site.Data.icons $name -}} | ||||
| {{- $attributes := .Get "attributes" | default "height=1em"}} | ||||
|  | ||||
| {{- if not $icon -}} | ||||
|   {{ errorf "icon %q not found" (.Get 0) }} | ||||
|   {{ errorf "icon %q not found" $name }} | ||||
| {{- end -}} | ||||
|  | ||||
| {{- $icon = replaceRE "<svg" (printf "<svg %s" $attributes) $icon -}} | ||||
|   | ||||
| @@ -3,7 +3,8 @@ | ||||
|     "dev:theme": "hugo server --logLevel=debug --config=hugo.yaml,../dev.toml --environment=theme --source=exampleSite --themesDir=../.. --disableFastRender -D --port 1313", | ||||
|     "dev": "hugo server --source=exampleSite --themesDir=../.. --disableFastRender -D --port 1313", | ||||
|     "build:css": "npx postcss --config postcss.config.js --env production assets/css/styles.css -o assets/css/compiled/main.css", | ||||
|     "build": "hugo --gc --minify --themesDir=../.. --source=exampleSite" | ||||
|     "build": "hugo --gc --minify --themesDir=../.. --source=exampleSite", | ||||
|     "metrics": "hugo --themesDir=../.. --source=exampleSite --templateMetrics --templateMetricsHints" | ||||
|   }, | ||||
|   "devDependencies": { | ||||
|     "@tailwindcss/nesting": "^0.0.0-insiders.565cd3e", | ||||
|   | ||||
| @@ -3,10 +3,10 @@ const colors = require('tailwindcss/colors') | ||||
| const makePrimaryColor = | ||||
|   l => | ||||
|     ({ opacityValue }) => { | ||||
|       if (opacityValue === undefined) { | ||||
|         return `hsl(var(--primary-hue) 100% ${l}%)` | ||||
|       } | ||||
|       return `hsl(var(--primary-hue) 100% ${l}% / ${opacityValue})` | ||||
|       return ( | ||||
|         `hsl(var(--primary-hue) var(--primary-saturation) ${l}%` + | ||||
|         (opacityValue ? ` / ${opacityValue})` : ')') | ||||
|       ) | ||||
|     } | ||||
|  | ||||
| /** @type {import('tailwindcss').Config} */ | ||||
| @@ -14,6 +14,11 @@ module.exports = { | ||||
|   content: [ | ||||
|     './**/hugo_stats.json', | ||||
|   ], | ||||
|   safelist: [ | ||||
|     'max-w-screen-xl', | ||||
|     'max-w-[90rem]', | ||||
|     'max-w-full' | ||||
|   ], | ||||
|   theme: { | ||||
|     screens: { | ||||
|       sm: '640px', | ||||
|   | ||||
		Reference in New Issue
	
	Block a user