Compare commits

..

41 Commits

Author SHA1 Message Date
Cell a9c7fc2641 refactor(layouts): extract sidebar asides into partials
- Extract aside-collection into layouts/_partials/single/aside-collection.html
- Extract aside-toc (with print button) into layouts/_partials/single/aside-toc.html
- Simplify single.html with partial calls
2026-08-28 15:26:49 +08:00
Cell 2d0b34b1c6 perf(assets): optimize TOC tracking and refactor heading numbers to CSS counters (#834)
* perf(assets): optimize TOC scroll tracking and collapse behavior

- Replace linear scan + getBoundingClientRect with cached offsets and binary search
- Add rAF throttle to syncTocActiveState for per-frame update limit
- Use diff-based has-active class updates to avoid visual flash
- Simplify collapse CSS (remove broken @supports grid-animation block)
- Replace scrollTop assignment with smooth scrollIntoView

* refactor(assets): replace template heading numbers with CSS counters

- Remove heading counter map and format logic from render-heading.html
- Add CSS counters for h2-h6 numbering via .heading-numbered::before
- Add CSS counters for TOC ol numbering via ::marker
- Use :has(:nth-child(10)) for adaptive ol padding by digit count
- Remove [params.heading.number.format] config (CSS uses fixed format)

* feat(layouts): add print button to sidebar TOC title

- Add print icon button next to TOC title text in sidebar
- Use event.stopPropagation() to prevent TOC toggle on click
- Add "print" i18n key to all 19 language files
- Style print button with secondary color and hover effect
2026-08-28 15:00:10 +08:00
Cell 0b2909c5a5 feat(layouts): add nav-dialog with tab switching for TOC and collections (#833)
* feat(layouts): add nav-dialog with tab switching for TOC and collections on mobile

Rename toc-dialog to nav-dialog and integrate collection list via
tab-element, so mobile users can switch between table of contents and
collection/series list in the drawer. Extract nav-dialog into a
dedicated partial. Add single.navigation i18n key for all languages.

* feat(collections): remove early exit for collections with less than two pages

* style(assets): add transition to collection-summary background-color
2026-08-27 11:22:48 +08:00
Cell 57f98b48c5 feat(assets): add isRTL to core module and fix tooltip placement for RTL
Add isRTL utility function in utils/dom.ts and expose it via CoreService
and window.fixit. Use isRTL to flip task list tooltip placement from
'right' to 'left' in RTL layouts.
2026-08-25 13:57:00 +08:00
Cell 1d07b40d08 refactor(layouts): remove Hugo Extended check, use warnidf for init warnings
SCSS now depends on Dart Sass (external) instead of Hugo Extended's
built-in LibSass, so the hugo.IsExtended check is no longer needed.
Also switches warnf to warnidf for encryption/pagefind warnings to
prevent duplicate messages.
2026-08-25 11:33:44 +08:00
Cell 47b7c969f1 feat(layouts): add post disclaimer/declaration feature (#832)
Add a lightweight disclaimer notice at the beginning of articles to
indicate content origin (AI-generated, repost, original, custom).

- Add params.disclaimer config with enable, type, content options
- Support 4 types: ai, repost, original, custom
- Add custom SVG icons for ai/repost/original types
- Add i18n translations for 20 languages
- Add shimmer animation effect with RTL and reduce-motion support
2026-08-24 17:51:58 +08:00
Cell 152e7fa5a2 chore: change sassdoc/typedoc output to local public/references/ 2026-08-24 01:51:22 +08:00
Cell df90a0eb96 docs: add RTL support and new languages to README
- Add RTL (Right-to-Left) layout to features section
- Add Arabic, Persian, Urdu to supported languages list
2026-08-24 00:43:35 +08:00
Cell 5f1e79f49c feat(i18n): add RTL support for Arabic, Persian and Urdu (#831)
* feat(i18n): add RTL support and Arabic/Persian translations

- Add `dir` attribute to `<html>` via `.Site.Language.Direction`
- Convert physical CSS properties to logical properties across ~30 SCSS files
- Add `[dir="rtl"]` overrides for elements that need physical direction (code blocks, translate, icons)
- Add `logical-direction.html` template function for config value normalization
- Add RTL-aware deprecation warnings for old "left"/"right" config values
- Rename github corner, TOC position, reading progress config values from "left"/"right" to "start"/"end"
- Add Arabic (ar.toml) and Persian (fa.toml) i18n translation files
- Update multilingual documentation with RTL language configuration guide

* feat(shortcodes): add RTL support for tabs and refactor border-radius mixin

- Rename tabs placement values from "left"/"right" to "start"/"end" with deprecation warnings
- Convert all physical directional properties in tabs SCSS to logical properties
- Add RTL overrides for translate and box-shadow in tabs
- Add "start"/"end" support to border-radius mixin using CSS logical properties
- Refactor fixit-decryptor to use border-radius(start/end) mixin

* feat(assets): add RTL support for toc-dialog slide animation

The mobile toc-dialog always slid in from the right (100vw). In RTL
mode it should slide from the left (-100vw), matching the
border-inline-start/margin-inline-end anchoring.

* feat(assets): add RTL support for post-tag comma separator

* refactor(assets): extract RTL styles into dedicated _rtl.scss

* feat(assets): add RTL support for theme-switch and directional icons

* feat(i18n): add RTL support and improve i18n

- Add RTL typography corrections for Arabic-script languages (:lang(ar/fa/ur))
- Remove fa-list-ol from RTL flip list (numbers get mirrored)
- Add Urdu translation file (i18n/ur.toml)
- Rename noMoretTranslations to noTranslations and simplify all translations
- Update json-viewer-element from 1.0.4 to 1.0.6
- Add RTL test posts (index.en.md, index.ar.md)
- Fix layout partials for RTL support

See https://fixit.lruihao.cn/docs/content-management/introduction/#rtl-language-support
2026-08-24 00:22:34 +08:00
Cell 8b6806bbf3 fix(layouts): hide end_flag when post content is encrypted 2026-08-19 12:41:05 +08:00
Cell c65852d882 fix(layouts): replace deprecated .Site.BuildDrafts with HUGO_PARAMS_MENU_DRAFT env var
Use getenv "HUGO_PARAMS_MENU_DRAFT" to control draft menu item visibility,
replacing the deprecated .Site.BuildDrafts (Hugo v0.156.0). (#702)

Also refactors menu range loops to use `continue` for reduced nesting.
2026-08-19 12:30:50 +08:00
Cell 224621b114 fix(post-chat-ai): correct variable name for upLoadWeb in postChatConfig 2026-08-19 09:52:20 +08:00
Cell e0940bd4d3 fix(layouts): resolve accessibility and SEO issues from AI crawler support (#830) 2026-08-17 12:47:50 +08:00
Cell 8782b46f53 docs: add China mirror (Gitee) section to README 2026-08-14 15:02:20 +08:00
Cell 9f378691f1 docs: add README for apps directory with development instructions 2026-08-14 12:45:34 +08:00
Cell 9f4d33a670 docs: add README for internal packages overview and development instructions 2026-08-14 12:41:43 +08:00
Cell 3c449a9017 refactor(assets): extract UnoCSS config into @hugo-fixit/unocss-preset package (#829)
Extract theme tokens, shortcuts, blocklist, safelist, and icon configuration
from uno.config.ts into a reusable workspace package at packages/unocss-preset/.

- Create @hugo-fixit/unocss-preset with presetFixIt and createFixItConfig()
- Simplify uno.config.ts to use createFixItConfig() with content/cli overrides
- Move unocss, @iconify/json from root devDependencies to preset package
2026-08-14 12:33:18 +08:00
dependabot[bot] 65e9f2ff92 chore(deps-dev): bump toml from 3.0.0 to 5.0.0 (#815) 2026-08-12 18:10:29 +08:00
Cell 54fe7bdc83 Merge pull request #814 from hugo-fixit/dependabot/npm_and_yarn/commander-15.0.0 2026-08-12 18:09:34 +08:00
dependabot[bot] 0bc1862853 chore(deps-dev): bump the npm-development group with 6 updates (#813)
Bumps the npm-development group with 6 updates:

| Package | From | To |
| --- | --- | --- |
| [@antfu/eslint-config](https://github.com/antfu/eslint-config) | `9.1.0` | `9.2.0` |
| [@iconify/json](https://github.com/iconify/icon-sets) | `2.2.502` | `2.2.507` |
| [concurrently](https://github.com/open-cli-tools/concurrently) | `10.0.3` | `10.0.4` |
| [eslint](https://github.com/eslint/eslint) | `10.7.0` | `10.8.0` |
| [lint-staged](https://github.com/lint-staged/lint-staged) | `17.1.0` | `17.2.0` |
| [fs-extra](https://github.com/jprichardson/node-fs-extra) | `11.3.6` | `11.4.0` |


Updates `@antfu/eslint-config` from 9.1.0 to 9.2.0
- [Release notes](https://github.com/antfu/eslint-config/releases)
- [Commits](https://github.com/antfu/eslint-config/compare/v9.1.0...v9.2.0)

Updates `@iconify/json` from 2.2.502 to 2.2.507
- [Commits](https://github.com/iconify/icon-sets/compare/2.2.502...2.2.507)

Updates `concurrently` from 10.0.3 to 10.0.4
- [Release notes](https://github.com/open-cli-tools/concurrently/releases)
- [Commits](https://github.com/open-cli-tools/concurrently/compare/v10.0.3...v10.0.4)

Updates `eslint` from 10.7.0 to 10.8.0
- [Release notes](https://github.com/eslint/eslint/releases)
- [Commits](https://github.com/eslint/eslint/compare/v10.7.0...v10.8.0)

Updates `lint-staged` from 17.1.0 to 17.2.0
- [Release notes](https://github.com/lint-staged/lint-staged/releases)
- [Changelog](https://github.com/lint-staged/lint-staged/blob/main/CHANGELOG.md)
- [Commits](https://github.com/lint-staged/lint-staged/compare/v17.1.0...v17.2.0)

Updates `fs-extra` from 11.3.6 to 11.4.0
- [Changelog](https://github.com/jprichardson/node-fs-extra/blob/master/CHANGELOG.md)
- [Commits](https://github.com/jprichardson/node-fs-extra/compare/11.3.6...11.4.0)

---
updated-dependencies:
- dependency-name: "@antfu/eslint-config"
  dependency-version: 9.2.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: npm-development
- dependency-name: "@iconify/json"
  dependency-version: 2.2.507
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: npm-development
- dependency-name: concurrently
  dependency-version: 10.0.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: npm-development
- dependency-name: eslint
  dependency-version: 10.8.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: npm-development
- dependency-name: lint-staged
  dependency-version: 17.2.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: npm-development
- dependency-name: fs-extra
  dependency-version: 11.4.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: npm-development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-12 18:01:24 +08:00
Cell b680d609a1 fix(scss): preserve mobile search modal height (#828) 2026-08-12 12:43:00 +08:00
Cell a9c29b1641 fix(scss): preserve bare CSS fallback values in fi-var
Solve the problem of losing the default background color of the "mark" tag
2026-08-12 11:25:11 +08:00
Cell 7bdd0c5869 fix: update manifest output condition to include server and non-production checks 2026-08-07 20:47:40 +08:00
dependabot[bot] 8d7703a418 chore(deps): bump actions/setup-node from 6 to 7 (#812)
Bumps [actions/setup-node](https://github.com/actions/setup-node) from 6 to 7.
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](https://github.com/actions/setup-node/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/setup-node
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-01 11:42:56 +08:00
dependabot[bot] da2f085969 chore(deps): bump github/codeql-action from 4 to 4.37.3 (#811)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 4 to 4.37.3.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/v4...v4.37.3)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 4.37.3
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-08-01 11:42:28 +08:00
Cell e3acdb9732 fix(workflow): pass GITHUB_TOKEN to gen-lexers step 2026-08-01 11:36:43 +08:00
dependabot[bot] ece55d0d36 chore(deps-dev): bump commander from 14.0.3 to 15.0.0
Bumps [commander](https://github.com/tj/commander.js) from 14.0.3 to 15.0.0.
- [Release notes](https://github.com/tj/commander.js/releases)
- [Changelog](https://github.com/tj/commander.js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/tj/commander.js/compare/v14.0.3...v15.0.0)

---
updated-dependencies:
- dependency-name: commander
  dependency-version: 15.0.0
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-01 01:25:15 +00:00
Cell a73416e2be chore(release): 1.0.0-alpha 2026-07-27 14:44:11 +08:00
Cell 9e2f388022 style(assets): use cooler and darker hover colors for menu items in dark mode 2026-07-26 04:14:46 +08:00
Cell 610fa1d561 fix(assets): apply correct json-viewer theme after content decryption 2026-07-26 02:08:02 +08:00
Cell a5a7b98c95 docs: update v1 migration guide and fixit-encrypt repository
- Update README warning to point to v1 migration guide
- Update version compatibility check for v1.0.0
- Remove temporary v1 development warning
- Update fixit-encrypt repository link in encrypt package README
2026-07-24 12:39:03 +08:00
Cell a5d24f395e refactor(assets): use ES6 # private fields instead of TS private
Convert all TypeScript `private` and `private readonly` declarations to
ES6 `#` syntax for true runtime privacy. TypeScript's `private` keyword
only provides compile-time checking but fields remain accessible in
compiled JavaScript.
2026-07-23 14:33:19 +08:00
Cell f5509e5b82 style(assets): rebuild unocss.css
Remove redundant CSS variable comments and add .ease-out utility.
2026-07-23 12:59:30 +08:00
Cell d35dd6a120 chore: clean up VSCode settings
Remove explorer.fileNesting config and fix comment casing.
2026-07-23 12:59:19 +08:00
Cell 5322a15ceb docs(layouts): add header comments to undocumented partials
Add `{{/* ... */}}` header comments to 25 partials that had no documentation,
enabling `pnpm gen:docs` to generate their reference docs. Also fix
base/head/index.html leading blank line that prevented parser matching.

Groups covered: base/, feed/, function/, home/, init/, plugin/, single/, store/, (root).
2026-07-23 12:56:40 +08:00
Cell a254e10136 chore(release): encrypt 0.3.1 2026-07-21 16:24:19 +08:00
Cell 15b415ff2e docs(encrypt): update Go implementation status to Available
Also fix shell command injection in bench.ts and simplify build script.
2026-07-21 16:23:08 +08:00
Cell 2c0b48370b feat(gen-docs): add Hugo partials docs generation (#809)
* feat(gen-docs): add documentation generation package with SassDoc and TypeDoc support

Add new `@hugo-fixit/gen-docs` package that parses Hugo config (hugo.toml) and generates
documentation. Includes SassDoc annotations for SCSS variables and mixins, TypeDoc config
for TypeScript source docs, and a `.sassdocrc` configuration file.

* docs(readme): add browsers support section

* feat(gen-docs): add Hugo partials docs generation and fix config empty sections

- Add partial-parser.ts: parses Hugo partial comment blocks (@param/@return/@example)
- Add partials.ts renderer: generates grouped Markdown with param tables
- Add `partials` subcommand with -t/-o options for template injection
- Fix config-parser: empty TOML sections (library.js/library.css) now retain descriptions
- Fix config-parser: correctly distinguish section-level vs key-level comments
- Update README with partials subcommand documentation
2026-07-21 12:19:07 +08:00
Cell e07eefd506 fix(layouts): fix busuanzi site views variable name in footer 2026-07-21 01:30:32 +08:00
Cell 7a28234de3 fix(styles): content style priority conflict 2026-07-21 00:38:02 +08:00
Cell 0d6af76f06 feat(layouts): add timeout and cache key options to get-remote-image partial 2026-07-19 15:33:15 +08:00
190 changed files with 5783 additions and 1926 deletions
+3 -3
View File
@@ -43,7 +43,7 @@ jobs:
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v4
uses: github/codeql-action/init@v4.37.3
with:
languages: ${{ matrix.language }}
config-file: ./.github/configs/codeql.yml
@@ -55,7 +55,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v4
uses: github/codeql-action/autobuild@v4.37.3
# ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
@@ -69,4 +69,4 @@ jobs:
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v4
uses: github/codeql-action/analyze@v4.37.3
+3 -1
View File
@@ -15,7 +15,7 @@ jobs:
uses: actions/checkout@v7
- uses: pnpm/action-setup@v6
- name: Setup Node.js
uses: actions/setup-node@v6
uses: actions/setup-node@v7
with:
node-version-file: .nvmrc
cache: pnpm
@@ -23,6 +23,8 @@ jobs:
run: pnpm install --frozen-lockfile
- name: Generate lexer map
run: pnpm gen:lexers
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Create Pull Request
uses: peter-evans/create-pull-request@v8
with:
+1 -1
View File
@@ -23,7 +23,7 @@ jobs:
- uses: pnpm/action-setup@v6
- name: Setup Node.js
uses: actions/setup-node@v6
uses: actions/setup-node@v7
with:
node-version-file: .nvmrc
registry-url: 'https://registry.npmjs.org'
+1 -1
View File
@@ -17,7 +17,7 @@ jobs:
- uses: pnpm/action-setup@v6
- name: Setup Node.js
uses: actions/setup-node@v6
uses: actions/setup-node@v7
with:
node-version-file: .nvmrc
cache: pnpm
+7
View File
@@ -0,0 +1,7 @@
{
"display": {
"access": ["public"],
"alias": false
},
"sort": ["group"]
}
+1 -9
View File
@@ -1,13 +1,5 @@
{
"todo-tree.tree.scanMode": "workspace only",
"explorer.fileNesting.enabled": true,
"explorer.fileNesting.patterns": {
"tsconfig.json": "tsconfig.*.json, env.d.ts",
"package.json": "package-lock.json, pnpm*, .npmrc, .nvmrc, .eslint*, eslint*, .editorconfig, librarybot.yml",
"README.md": "README.*.md, CODE_OF_CONDUCT.md, CONTRIBUTING.md, LICENSE, SECURITY.md, CHANGELOG.md",
"hugo.toml": "theme.toml, .hugo_build.lock",
"vercel.json": "build.sh"
},
"files.associations": {
"*.template.ts": "gots",
"*.template.js": "gojs",
@@ -18,7 +10,7 @@
"**/layouts/**/*.xml": "gohtml",
"**/layouts/**/*.md": "gotemplate"
},
// Disable the default formatter, use eslint instead
// Disable the default formatter, use ESLint instead
"prettier.enable": false,
"editor.formatOnSave": false,
// Auto fix
+1
View File
@@ -106,6 +106,7 @@ Hugo Pipes processes all assets. The key orchestration is in `_partials/base/ass
- CSS classes: BEM or semantic naming (`header-desktop`, `menu-item`)
- SCSS variables: hyphen-separated, semantic (`$global-font-family`)
- CSS custom properties: prefixed with `fi-` / `--fi-`
- Use `fi-var()` function to reference CSS custom properties (auto-adds `--fi-` prefix), never use `var(--fi-...)` directly
- Use CSS variables for theme switching; SCSS variables for colors (no hardcoded values)
- Prefer relative units (rem, em, %) over absolute units
- Keep selector nesting shallow
+21 -5
View File
@@ -32,9 +32,8 @@
[![Gitee star of FixIt](https://gitee.com/lruihao/FixIt/badge/star.svg)](https://gitee.com/lruihao/FixIt/stargazers)
> [!WARNING]
> **Version v0.x only accepts bug fixes. For new feature submissions, please develop on the [v1](https://github.com/hugo-fixit/FixIt/tree/v1) branch.**
>
> Version 1.0 is planned for release in **the first half of 2027**. Welcome to join the development and discussion! See [v1 Milestone](https://github.com/hugo-fixit/FixIt/milestone/8) for details.
> **The `main` branch contains the v1 code. For upgrade instructions, see the [v1 migration guide](https://fixit.lruihao.cn/guides/upgrade-to-v1/).**\
> Version 1.0.0 is planned for release in **the first half of 2027**. Welcome to join the development and [discussion](https://github.com/orgs/hugo-fixit/discussions/723)!
## Live Preview
@@ -106,10 +105,11 @@ Click the following links to generate a new repository with template:
- **Responsive** layout
- **Light/Dark** mode
- **RTL (Right-to-Left)** layout supported
- Globally consistent **design language**
- **Pagination** supported
- Easy-to-use and self-expanding **table of contents**
- **Multilanguage** supported and i18n ready
- **Multilanguage** supported and I18n ready
- Beautiful **CSS animation**
### Social and Comment Systems
@@ -168,7 +168,7 @@ Click the following links to generate a new repository with template:
</details>
## Multilingual and i18n
## Multilingual and I18n
FixIt supports multilingual and i18n. For more information, see the [Content Management](https://fixit.lruihao.cn/docs/content-management/introduction#multilingual) documentation. You are welcome to [contribute with a new language](https://github.com/hugo-fixit/FixIt/pulls).
@@ -191,9 +191,21 @@ FixIt supports multilingual and i18n. For more information, see the [Content Man
- Hindi
- Japanese
- Korean
- Arabic
- Persian
- Urdu
</details>
## Browsers Support
The FixIt theme supports the last two versions of all major browsers.
![Chrome](https://img.shields.io/badge/Chrome-last+2-blue?logo=googlechrome)
![Edge](https://img.shields.io/badge/Edge-last+2-blue?logo=microsoft-edge)
![Firefox](https://img.shields.io/badge/Firefox-last+2-orange?logo=firefox)
![Safari](https://img.shields.io/badge/Safari-last+2-blue?logo=safari)
## Theme Components
To balance **simplicity** and **extensibility**, FixIt theme provides extra [Hugo theme components](https://fixit.lruihao.cn/ecosystem/#-components) for customization.
@@ -252,6 +264,10 @@ All feedback is welcome! Head over to the [discussions][discussions], [Pull requ
[qq-group]: https://qm.qq.com/q/Mn1I7ljqsS
[dev-group]: https://qm.qq.com/q/ky3uru0mbu
## China Mirror
A mirror is available on Gitee for users in mainland China: [gitee.com/lruihao/FixIt](https://gitee.com/lruihao/FixIt)
## Contributing
We welcome you to join the development of FixIt. Please see [contributing document](/CONTRIBUTING.md). 🤗
+19 -3
View File
@@ -32,9 +32,8 @@
[![Gitee star of FixIt](https://gitee.com/lruihao/FixIt/badge/star.svg)](https://gitee.com/lruihao/FixIt/stargazers)
> [!WARNING]
> **v0.x 版本仅接受 bug 修复,如需提交新功能,请基于 [v1](https://github.com/hugo-fixit/FixIt/tree/v1) 分支开发。**
>
> 1.0 版本计划在 **2027 年上半年** 发布,欢迎加入开发和讨论!详见 [v1 里程碑](https://github.com/hugo-fixit/FixIt/milestone/8)。
> **当前 `main` 分支包含 v1 代码,升级详见 [v1 升级指南](https://fixit.lruihao.cn/guides/upgrade-to-v1/)**。\
> 1.0 版本计划在 **2027 年上半年** 发布,欢迎加入开发和 [讨论](https://github.com/orgs/hugo-fixit/discussions/723)
## 即时预览
@@ -106,6 +105,7 @@ pnpx fixit-cli create my-blog
- **响应式** 布局
- **浅色/深色** 主题模式
- 支持 **RTL(从右到左)** 布局
- 全局一致的 **设计语言**
- 支持 **分页**
- 易用和自动展开的 **文章目录**
@@ -191,9 +191,21 @@ FixIt 主题多语言基本配置及自动翻译等详见 [内容管理](https:/
- 印地语
- 日语
- 韩语
- 阿拉伯语
- 波斯语
- 乌尔都语
</details>
## 浏览器支持
FixIt 主题支持所有主流浏览器的最近两个版本。
![Chrome](https://img.shields.io/badge/Chrome-last+2-blue?logo=googlechrome)
![Edge](https://img.shields.io/badge/Edge-last+2-blue?logo=microsoft-edge)
![Firefox](https://img.shields.io/badge/Firefox-last+2-orange?logo=firefox)
![Safari](https://img.shields.io/badge/Safari-last+2-blue?logo=safari)
## 主题组件
为了平衡 FixIt 主题的 **简洁性****可扩展性**,我们额外开发了一系列 [Hugo 主题组件](https://fixit.lruihao.cn/zh-cn/ecosystem/#-组件) 供用户选择。
@@ -252,6 +264,10 @@ FixIt 主题多语言基本配置及自动翻译等详见 [内容管理](https:/
[qq-group]: https://qm.qq.com/q/Mn1I7ljqsS
[dev-group]: https://qm.qq.com/q/ky3uru0mbu
## 中国区镜像
为方便中国大陆用户访问,FixIt 在 Gitee 上提供了镜像仓库:[gitee.com/lruihao/FixIt](https://gitee.com/lruihao/FixIt)
## 参与贡献
我们欢迎你加入 FixIt 的开发,贡献出你的一份力量。请看开源 [贡献指南](/CONTRIBUTING.md)。 🤗
+25
View File
@@ -0,0 +1,25 @@
# Apps
This directory contains the Hugo sites used for development, testing, and demonstration of the [FixIt](https://fixit.lruihao.cn) theme.
## Overview
| App | Description | Live |
| -------------- | ----------------------------------------------------- | ----------------------------------------------------------------- |
| [demo](./demo) | Demo site showcasing FixIt theme features | [demo.fixit.lruihao.cn](https://demo.fixit.lruihao.cn) |
| [test](./test) | Test site for exercising and verifying theme features | [demo.fixit.lruihao.cn/test](https://demo.fixit.lruihao.cn/test/) |
> [!NOTE]
> The documentation site (`fixit-docs`) lives in a separate repository: [hugo-fixit/fixit-docs](https://github.com/hugo-fixit/fixit-docs).
## Development
From the repository root:
```bash
pnpm dev:demo # Start demo site dev server
pnpm dev:test # Start test site dev server
pnpm build:demo # Build demo site
pnpm build:test # Build test site
pnpm build # Build all sites (merged into public/)
```
@@ -26,6 +26,17 @@ $$ \ce{CO2 + C -> 2 CO} $$
$$ \ce{Hg^2+ ->[I-] HgI2 ->[I-] [Hg^{II}I4]^2-} $$
## JSON
```json
{
"name": "fixit",
"version": "1.0.0",
"description": "A Hugo theme for creating encrypted content.",
"author": "Lruihao"
}
```
## style
{{< style "text-align:right; strong{color:#00b1ff;}" >}}
@@ -0,0 +1,189 @@
---
title: اختبار دعم اللغة العربية والكتابة من اليمين إلى اليسار
date: 2026-08-23T10:00:00+08:00
collections:
- اختبارات
categories:
- ميزات
tags:
- RTL
- عربي
- اختبار
---
هذا مقال اختباري شامل لدعم اللغة العربية والكتابة من اليمين إلى اليسار في سمة [FixIt](https://github.com/hugo-fixit/FixIt/). يهدف هذا المقال إلى اختبار جميع عناصر الويب المختلفة مع المحتوى العربي.
<!--more-->
## المقدمة
مرحباً بكم في هذا المقال الاختباري الشامل. اللغة العربية هي واحدة من أكثر اللغات انتشاراً في العالم، وتتميز بكتابتها من اليمين إلى اليسار. يتطلب دعم هذه اللغة في تصميمات الويب اهتماماً خاصاً بالعديد من الجوانب التقنية.
### لماذا RTL مهم؟
عندما نصمم مواقع ويب تدعم اللغات التي تُكتب من اليمين إلى اليسار، يجب علينا مراعاة عدة عوامل:
- **اتجاه النص**: يجب أن يتدفق النص بشكل طبيعي من اليمين إلى اليسار
- **تخطيط الصفحة**: يجب أن تكون العناصر مرتبة بشكل منطقي
- **الرموز والأيقونات**: قد تحتاج بعضها إلى انعكاس
- **التباعد بين الأسطر**: يحتاج النص العربي إلى مساحة أكبر للتشكيل
## النص المختلط
هذا نص يحتوي على كلمات إنجليزية مثل JavaScript و HTML و CSS مع نص عربي. يجب أن يظهر كل شيء بشكل صحيح.
## الروابط
- [موقع Hugo](https://gohugo.io)
- [سمة FixIt](https://fixit.lruihao.cn)
- [وثائق RTL](https://rtlstyling.com)
## القوائم
القوائم غير المرتبة:
- عنصر القائمة الأول
- عنصر القائمة الثاني
- عنصر القائمة الثالث
- عنصر فرعي
- عنصر فرعي آخر
القوائم المرتبة:
1. الخطوة الأولى في العملية
2. الخطوة الثانية
3. الخطوة الثالثة والأخيرة
قوائم المهام:
- [x] إعداد بيئة التطوير
- [x] كتابة المحتوى الأساسي
- [ ] اختبار التوافق مع المتصفحات
- [ ] مراجعة التصميم النهائي
- [ ] نشر الموقع
## الجداول
| اللغة | الاتجاه | الحروف المتصلة |
| ---------: | ------: | -------------: |
| العربية | RTL | نعم |
| الفارسية | RTL | نعم |
| العبرية | RTL | لا |
| الإنجليزية | LTR | لا |
## الاقتباسات
> العلم نور والجهل ظلام
> — مثل عربي
اقتباس طويل:
> إن الله لا يغير ما بقوم حتى يغيروا ما بأنفسهم وإذا أراد الله بقوم سوءاً فلا مرد له وما لهم من دونه من وال
## الأيقونات
أيقونات يتم قلبها في RTL:
- :(fa-solid fa-tag): وسم
- :(fa-solid fa-tags): وسوم
- :(fa-solid fa-folder): مجلد
- :(fa-solid fa-folder-open): مجلد مفتوح
- :(fa-solid fa-pen-to-square): قلم تعديل
أيقونات لا يتم قلبها في RTL:
- :(fa-solid fa-share): مشاركة
- :(fa-solid fa-search): بحث
## التبويبات
{{< tabs >}}
{{% tab title="العلامة الأولى" %}}
محتوى التبويب الأول.
{{% /tab %}}
{{% tab title="العلامة الثانية" %}}
محتوى التبويب الثاني.
{{% /tab %}}
{{< /tabs >}}
## التفاصيل القابلة للطي
<details>
<summary>انقر لعرض التفاصيل</summary>
هذا محتوى مخفي يمكنBOOLE توسيعه بالنقر.
المحتوى يمكن أن يكون نصاً أو كوداً أو أي عنصر آخر.
</details>
## التنبيهات
{{< admonition >}}
هذا تنبيه عادي يحتوي على معلومات مفيدة للمستخدم.
{{< /admonition >}}
> [!IMPORTANT]
> تأكد من اختبار جميع التغييرات قبل النشر.
## المحتوى المشفر
{{< fixit-encryptor password="1212" message="أدخل كلمة المرور (1212) لعرض المحتوى" >}}
هذا محتوى مشفر. يجب إدخال كلمة المرور لعرضه.
{{< /fixit-encryptor >}}
## أمثلة على المحتوى LTR
في صفحة RTL، بعض العناصر تبقى باتجاه LTR لأن محتاها لغوي بحت أو برمجي. فيما يلي أمثلة:
### كتلة الكود
```c
#include <stdio.h>
int main() {
printf("Hello, World!\n");
return 0;
}
```
### عارض JSON
```json
{
"name": "FixIt",
"version": "1.0.0",
"features": ["RTL", "i18n", "shortcodes"]
}
```
### تبويبات الكود
```python {group=tab1}
print("Python")
```
```go {group=tab1}
fmt.Println("Go")
```
### الصيغ الرياضية
معادلة بسيطة: $E = mc^2$
معادلة معقدة:
$$\sum_{i=1}^{n} i = \frac{n(n+1)}{2}$$
### مخططات Mermaid
```mermaid
graph LR
A[بداية] --> B[عملية]
B --> C[نهاية]
```
---
{.awesome-hr}
_تم إنشاء هذا المقال لاختبار دعم اللغة العربية في سمة FixIt._
@@ -0,0 +1,187 @@
---
title: Arabic RTL Test
date: 2026-08-23T10:00:00+08:00
collections:
- Tests
categories:
- Features
tags:
- RTL
- Arabic
---
A comprehensive test article for Arabic language and Right-to-Left layout support in the [FixIt](https://github.com/hugo-fixit/FixIt/) theme. This article tests various web elements with Arabic content.
<!--more-->
## Introduction
Welcome to this comprehensive test article. Arabic is one of the most widely spoken languages in the world, characterized by its Right-to-Left writing direction. Supporting this language in web designs requires special attention to many technical aspects.
### Why RTL Matters
When designing websites that support Right-to-Left languages, we need to consider several factors:
- **Text direction**: Text should flow naturally from right to left
- **Page layout**: Elements should be arranged in a logical order
- **Symbols and icons**: Some may need to be mirrored
- **Line spacing**: Arabic text needs more space for diacritics
## Mixed Text
This text contains English words like JavaScript, HTML, and CSS alongside Arabic text. Everything should display correctly.
## Links
- [Hugo Website](https://gohugo.io)
- [FixIt Theme](https://fixit.lruihao.cn)
- [RTL Styling](https://rtlstyling.com)
## Lists
Unordered lists:
- First list item
- Second list item
- Third list item
- Sub item
- Another sub item
Ordered lists:
1. First step in the process
2. Second step
3. Third and final step
Task lists:
- [x] Set up development environment
- [x] Write basic content
- [ ] Test browser compatibility
- [ ] Review final design
- [ ] Deploy website
## Tables
| Language | Direction | Connected Letters |
| ---------- | --------- | ----------------- |
| Arabic | RTL | Yes |
| Persian | RTL | Yes |
| Hebrew | RTL | No |
| English | LTR | No |
## Blockquotes
> Knowledge is light and ignorance is darkness
> — Arabic proverb
Long quote:
> Indeed, Allah does not change the condition of a people until they change what is in themselves
## Icons
Icons that are flipped in RTL:
- :(fa-solid fa-tag): Tag
- :(fa-solid fa-tags): Tags
- :(fa-solid fa-folder): Folder
- :(fa-solid fa-folder-open): Folder Open
- :(fa-solid fa-pen-to-square): Edit
Icons that are NOT flipped in RTL:
- :(fa-solid fa-share): Share
- :(fa-solid fa-search): Search
## Tabs
{{< tabs >}}
{{% tab title="First Tab" %}}
Content of the first tab.
{{% /tab %}}
{{% tab title="Second Tab" %}}
Content of the second tab.
{{% /tab %}}
{{< /tabs >}}
## Collapsible Details
<details>
<summary>Click to show details</summary>
This is hidden content that can be expanded by clicking.
Content can be text, code, or any other element.
</details>
## Alerts
{{< admonition >}}
This is a regular admonition with useful information for the user.
{{< /admonition >}}
> [!IMPORTANT]
> Make sure to test all changes before deploying.
## Encrypted Content
{{< fixit-encryptor password="1212" message="Enter password (1212) to view content" >}}
This is encrypted content. You must enter the password to view it.
{{< /fixit-encryptor >}}
## LTR Content Examples
In an RTL page, some elements remain in LTR direction because their content is purely linguistic or programmatic. Here are examples:
### Code Block
```c
#include <stdio.h>
int main() {
printf("Hello, World!\n");
return 0;
}
```
### JSON Viewer
```json
{
"name": "FixIt",
"version": "1.0.0",
"features": ["RTL", "i18n", "shortcodes"]
}
```
### Code Tabs
```python {group=tab1}
print("Python")
```
```go {group=tab1}
fmt.Println("Go")
```
### Math
Simple equation: $E = mc^2$
Complex equation:
$$\sum_{i=1}^{n} i = \frac{n(n+1)}{2}$$
### Mermaid Diagram
```mermaid
graph LR
A[Start] --> B[Process]
B --> C[End]
```
---
_Created to test Arabic language support in the FixIt theme._
@@ -34,7 +34,7 @@ See Types section for various test cases.
### Underline (Default)
<!-- placement: top, bottom, left, right -->
<!-- placement: top, bottom, start, end -->
{{< tabs placement="top" >}}
{{% tab title="Tab 1" %}}Content for underline style tab 1{{% /tab %}}
@@ -44,7 +44,7 @@ See Types section for various test cases.
### Pill
<!-- placement: top, bottom, left, right -->
<!-- placement: top, bottom, start, end -->
{{< tabs type="pill" placement="top" >}}
{{% tab title="Tab 1" %}}Content for pill style tab 1{{% /tab %}}
@@ -54,7 +54,7 @@ See Types section for various test cases.
### Card
<!-- placement: top, bottom, left, right -->
<!-- placement: top, bottom, start, end -->
{{< tabs type="card" placement="top" >}}
{{% tab title="Tab 1" %}}Content for card style tab 1{{% /tab %}}
@@ -126,7 +126,7 @@ Nested tab C with a table:
{{% tab title="Outer Tab 3" %}}
This tab contains vertical nested tabs:
{{< tabs type="card" placement="left" >}}
{{< tabs type="card" placement="end" >}}
{{% tab title="Vertical A" %}}
Content for vertical nested tab A.
+14 -5
View File
@@ -5,20 +5,29 @@
title = "FixIt TEST"
baseURL = "https://demo.fixit.lruihao.cn/test/"
ignoreLogs = [ "warning-file-tree" ]
ignoreLogs = [
"warning-file-tree",
"warning-encryption"
]
defaultContentLanguage = "en"
# test for multilingual support
# [languages]
[languages]
# [languages.en]
# locale = "en"
# label = "English"
[languages.en]
locale = "en"
label = "English"
# [todo] 优化中文排版
# [languages.zh-cn]
# locale = "zh-CN"
# label = "简体中文"
[languages.ar]
direction = "rtl"
locale = "ar"
label = "العربية"
[permalinks]
[permalinks.page]
+13 -12
View File
@@ -58,11 +58,11 @@
.whitespace-nowrap{white-space:nowrap;}
.b,
.border{border-width:1px;}
.bg-danger{background-color:var(--fi-danger) /* var(--fi-danger) */;}
.bg-info{background-color:var(--fi-info) /* var(--fi-info) */;}
.bg-primary{background-color:var(--fi-primary) /* var(--fi-primary) */;}
.bg-success{background-color:var(--fi-success) /* var(--fi-success) */;}
.bg-warning{background-color:var(--fi-warning) /* var(--fi-warning) */;}
.bg-danger{background-color:var(--fi-danger);}
.bg-info{background-color:var(--fi-info);}
.bg-primary{background-color:var(--fi-primary);}
.bg-success{background-color:var(--fi-success);}
.bg-warning{background-color:var(--fi-warning);}
.px{padding-left:1rem;padding-right:1rem;}
.pl{padding-left:1rem;}
.pt{padding-top:1rem;}
@@ -73,13 +73,13 @@
.text-5xl{font-size:3rem;line-height:1;}
.text-base{font-size:1rem;line-height:1.5rem;}
.text-lg{font-size:1.125rem;line-height:1.75rem;}
.text-danger{color:var(--fi-danger) /* var(--fi-danger) */;}
.text-info{color:var(--fi-info) /* var(--fi-info) */;}
.text-primary{color:var(--fi-primary) /* var(--fi-primary) */;}
.text-secondary{color:var(--fi-secondary) /* var(--fi-secondary) */;}
.text-success{color:var(--fi-success) /* var(--fi-success) */;}
.text-warning{color:var(--fi-warning) /* var(--fi-warning) */;}
.text-white{--un-text-opacity:1;color:rgb(255 255 255 / var(--un-text-opacity)) /* #fff */;}
.text-danger{color:var(--fi-danger);}
.text-info{color:var(--fi-info);}
.text-primary{color:var(--fi-primary);}
.text-secondary{color:var(--fi-secondary);}
.text-success{color:var(--fi-success);}
.text-warning{color:var(--fi-warning);}
.text-white{--un-text-opacity:1;color:rgb(255 255 255 / var(--un-text-opacity));}
.font-bold{font-weight:700;}
.capitalize{text-transform:capitalize;}
.lining-nums{--un-numeric-figure:lining-nums;font-variant-numeric:var(--un-ordinal) var(--un-slashed-zero) var(--un-numeric-figure) var(--un-numeric-spacing) var(--un-numeric-fraction);}
@@ -91,6 +91,7 @@
.opacity-50{opacity:0.5;}
.shadow{--un-shadow:var(--un-shadow-inset) 0 1px 3px 0 var(--un-shadow-color, rgb(0 0 0 / 0.1)),var(--un-shadow-inset) 0 1px 2px -1px var(--un-shadow-color, rgb(0 0 0 / 0.1));box-shadow:var(--un-ring-offset-shadow), var(--un-ring-shadow), var(--un-shadow);}
.blur{--un-blur:blur(8px);filter:var(--un-blur) var(--un-brightness) var(--un-contrast) var(--un-drop-shadow) var(--un-grayscale) var(--un-hue-rotate) var(--un-invert) var(--un-saturate) var(--un-sepia);}
.ease-out{transition-timing-function:cubic-bezier(0, 0, 0.2, 1);}
@media print{
.print\:hidden{display:none;}
}
+2 -2
View File
@@ -34,8 +34,8 @@ libFiles:
gitalkJS: gitalk@1.8.0/dist/gitalk.min.js
# instant.page@5.2.0 https://github.com/instantpage/instant.page
instantPage: instant.page@5.2.0/instantpage.min.js
# json-viewer-element@1.0.4 https://github.com/Lruihao/json-viewer-element
jsonViewerElementJS: json-viewer-element@1.0.4/dist/json-viewer-element.umd.js
# json-viewer-element@1.0.6 https://github.com/Lruihao/json-viewer-element
jsonViewerElementJS: json-viewer-element@1.0.6/dist/json-viewer-element.umd.js
# katex@0.17.0 https://github.com/KaTeX/KaTeX
katexCopyTexJS: katex@0.17.0/dist/contrib/copy-tex.min.js
katexCSS: katex@0.17.0/dist/katex.min.css
+2 -2
View File
@@ -34,8 +34,8 @@ libFiles:
gitalkJS: gitalk@1.8.0/dist/gitalk.min.js
# instant.page@5.2.0 https://github.com/instantpage/instant.page
instantPage: instant.page@5.2.0/instantpage.js
# json-viewer-element@1.0.4 https://github.com/Lruihao/json-viewer-element
jsonViewerElementJS: json-viewer-element@1.0.4/dist/json-viewer-element.umd.js
# json-viewer-element@1.0.6 https://github.com/Lruihao/json-viewer-element
jsonViewerElementJS: json-viewer-element@1.0.6/dist/json-viewer-element.umd.js
# katex@0.17.0 https://github.com/KaTeX/KaTeX
katexCopyTexJS: katex@0.17.0/dist/contrib/copy-tex.min.js
katexCSS: katex@0.17.0/dist/katex.min.css
+1
View File
@@ -0,0 +1 @@
<svg height="200" viewBox="0 0 1024 1024" width="200" xmlns="http://www.w3.org/2000/svg"><path d="m165.092285 116.164732c-25.344127 4.565483-52.891625 20.150029-71.782258 40.613251-7.39749 8.184825-12.434949 15.741121-18.575209 28.491493-14.638385 29.753014-13.537836 3.462746-13.065796 326.63738l.471998 284.136138 3.621509 11.804231c14.797126 47.856269 52.734987 81.226502 100.432514 88.15414 15.269124 2.203371 164.184377 2.046753 172.841242-.158763 17.472495-4.406741 29.278872-24.556749 24.715513-41.872626-2.205516-8.341486-10.390385-19.04725-17.47464-23.297374-5.352882-2.990749-8.500248-3.147366-88.939372-3.934744l-83.429872-.787378-10.547002-5.194119c-11.962994-5.82488-20.150051-14.325128-25.974888-26.603503l-3.775981-8.184868-.158784-275.949125c-.156596-151.747239.31538-278.467876 1.102779-281.46077 4.565505-20.93524 23.138612-38.407734 45.178756-42.50122 4.87876-.944016 108.302002-1.574777 267.605493-1.574777 259.105246 0 259.577244 0 269.33897 3.306129 11.963037 4.093485 22.351276 11.490997 29.120108 20.937386 11.019043 15.269123 10.390428 7.869488 11.334423 140.412859l.787378 119.636382 4.247978 6.453495c12.909136 19.521393 37.15265 23.456094 53.522386 8.659075 12.909136-11.649867 12.278375-3.304048 12.278375-137.737555 0-131.129524 0-131.601522-9.759624-154.898896-16.056501-38.881834-55.410376-69.104787-98.855613-76.030279-6.768875-.943953-101.533127-1.574713-276.264505-1.41595-218.335377.156617-268.236254.471997-277.995878 2.359988z"/><path d="m250.725528 303.805245c-13.694367 5.663972-22.353378 18.257727-22.509996 32.739472 0 11.021145 6.453495 23.29952 15.584504 29.753014l6.768875 4.722122h317.034309l6.612386-4.406741c10.231557-6.768875 15.110296-15.269124 15.741057-27.862879.471998-8.343631 0-11.806377-2.675368-16.841733-4.09355-8.030396-14.009748-16.687262-22.037999-19.049396-4.408887-1.415993-46.753511-1.88799-156.943504-1.731373-138.527014 0-151.434004.31538-157.574264 2.675369z"/><path d="m246.947402 467.515521c-23.769372 12.437095-25.028747 47.066703-2.359988 60.919791l7.71287 4.7221 104.680493.472126 104.526021.31538 8.341486-3.776002c23.140756-10.54919 27.706218-42.188135 8.500248-58.244551-10.705765-9.130944-7.08417-8.817774-119.479764-8.817774h-103.577735z"/><path d="m634.191337 520.565867c-10.705743 3.46281-22.040058 11.649759-27.547412 19.832482-2.677428 3.936932-9.289772 17.79002-14.640509 30.69701-5.509499 12.909135-20.778623 48.956881-34.003138 80.123743-13.22237 31.169093-29.435489 69.420039-35.88907 85.004628-33.844289 81.069884-45.178583 107.830005-49.113413 116.489016-8.028251 17.944492-6.927638 32.739472 3.462703 44.704612 7.240916 8.500248 16.056545 12.593755 26.916781 12.750372 10.390384 0 18.262018-3.303983 25.816125-10.547001 5.82488-5.666117 10.075004-14.797126 30.225012-63.438628l5.350737-13.378987 83.273255-.471998 83.114492-.31538 12.437138 30.222867c15.584503 38.0945 20.150008 46.753511 26.76012 51.319015 24.715512 16.841734 58.08789-.158763 58.08789-29.594251 0-7.712871-3.306129-16.528499-30.381629-81.069885-16.687262-39.825873-36.206509-86.577238-43.445237-103.893115-17.173505-41.437466-34.437226-82.837515-51.791013-124.19974-7.556253-17.79002-10.705764-23.29952-16.843879-29.596397-13.53775-13.853131-35.103751-19.991246-51.790927-14.638363zm27.388821 131.755993c6.453495 15.897739 18.259937 44.389232 26.131505 63.28201 7.871634 19.04725 14.166366 34.788371 13.853217 35.101606-.315402.31538-24.715598.31538-53.99447.158763l-53.520305-.471998 18.575317-43.290765c10.072794-23.769371 22.194616-52.262946 26.76012-63.279864 4.565505-11.018999 8.815629-20.150008 9.287626-20.150008.471912 0 6.296921 12.909178 12.90699 28.650256z"/><path d="m915.806665 519.937252c-7.712871 2.201225-18.418635 11.647614-21.881382 19.360549-2.831985 6.13805-2.990748 14.638363-2.990748 174.887931 0 159.621017.158763 168.74988 2.990748 174.731378 3.462747 7.871633 13.537751 17.159259 21.409384 19.67801 15.112506 5.035357 33.687758-2.205516 42.501241-16.371881l4.724267-7.712871v-169.380641c0-162.29424-.158762-169.535113-2.992894-174.887995-8.813483-16.685203-26.916737-25.028748-43.760616-20.306626z"/></svg>

After

Width:  |  Height:  |  Size: 4.0 KiB

@@ -0,0 +1 @@
<svg height="200" viewBox="0 0 1024 1024" width="200" xmlns="http://www.w3.org/2000/svg"><path d="m148.657996 137.18126c-21.954134 5.753981-36.643845 13.627683-51.784116 27.708051-16.504717 15.597267-26.498097 32.556836-32.252122 54.965778-3.029315 11.810553-3.181662 15.747404-3.181662 289.818747 0 273.916872.152347 278.003903 3.181662 289.816601 10.448189 40.730854 38.45883 69.803481 80.25169 82.978523l11.355724 3.482021h261.956139l6.208854-3.331842c21.349104-11.508048 26.498183-36.493644 11.053219-54.056076-11.508049-13.022717-2.272046-12.265383-144.453471-12.567887l-125.678897-.45483-9.843178-4.844365c-10.900894-5.603844-19.531931-15.29472-22.561268-25.742929-1.514669-4.694186-1.817173-69.803481-1.664827-276.49138.150158-267.557839.150158-270.434851 3.179474-277.248714 4.089198-9.238191 12.567909-17.869227 21.803955-22.258763l7.573386-3.634346h260.439282c249.995406 0 260.746121.150179 266.650325 2.874867 14.38506 6.513504 22.561267 17.716902 25.135775 34.828795 3.331927 21.196779 13.930231 32.704827 32.101855 34.522001 21.804041 2.274148 40.730962-18.622271 38.156454-42.093198-5.449374-47.999547-39.218331-86.160185-87.065553-98.423422-10.903039-2.724687-20.746154-2.87491-275.583865-2.724687-251.96276 0-264.831006.150179-274.978835 2.874866z"/><path d="m237.99553 314.493985c-12.567887 3.632201-21.954112 17.564578-21.954112 32.402323 0 16.202234 9.386225 28.770121 24.831124 33.311981 11.508049 3.484167 291.938425 3.331842 303.598756-.150179 14.382958-4.239356 24.376338-17.716903 24.376338-33.009477-.15018-13.627727-7.266547-24.833271-19.986824-31.344629-5.449396-2.724687-11.20548-2.874867-155.961456-2.724687-82.676017 0-152.329318.757334-154.903826 1.512523z"/><path d="m787.496268 359.011511c-20.289265 4.389535-39.518755 15.14025-55.115829 30.887654-7.721463 7.723458-19.986846 24.076022-37.853992 50.12137-48.301988 70.71314-72.832754 106.294979-104.932507 152.932183-55.115979 79.799048-68.443347 100.240595-70.865486 108.266622-3.331885 11.658228-2.424328 34.369675 3.784483 87.065553 9.238191 79.494356 9.388371 80.55634 18.626562 90.094891 7.116368 7.268693 16.047763 11.355723 25.133629 11.355723 4.089177 0 39.823341-7.116368 79.496502-15.897584 80.25169-17.869227 87.368143-20.139085 101.148109-33.768957 4.089176-4.08703 14.232735-16.957422 22.561267-28.770121 8.328532-11.808408 28.012787-39.368511 43.610012-61.172444 15.747404-21.95407 29.677635-41.488188 31.039979-43.607866 1.362344-2.119614 8.328532-11.962836 15.597225-21.956258 17.714757-24.680946 50.119225-70.25831 52.843912-74.497666 1.212164-1.817173 7.723522-11.053219 14.537385-20.44159 19.229426-26.802768 21.803934-30.889863 26.345794-41.943018 12.720213-31.042124 12.115203-64.201824-1.817173-94.486571-9.841055-21.198924-24.680946-37.248833-56.478259-61.324769-23.621106-17.716902-45.577364-29.375131-62.384608-32.859297-12.567887-2.724688-32.859297-2.724688-45.27486 0zm37.553483 71.013499c8.176207 3.484167 42.095343 27.710282 51.483714 36.948473 15.597225 15.14025 20.744094 34.522001 13.627726 50.724235-2.724687 6.056529-10.750714 18.019342-23.470927 34.979039-1.967352 2.724623-4.08703 1.36228-36.036668-22.108647-18.624417-13.627727-42.550173-31.192304-53.300888-38.913595-10.598389-7.723609-19.53193-14.537472-19.98676-15.142481-.605009-1.212164 19.98676-31.797313 25.43828-37.703663 8.631037-9.538593 29.82996-13.930231 42.245523-8.783361zm-81.766359 123.559197c11.962879 8.783361 33.614487 24.680945 48.151873 35.281523 9.976559 7.27352 19.919951 14.592308 29.82996 21.956215l3.482021 2.574465-15.597224 21.347001c-8.478712 11.660373-36.944183 51.181209-63.139797 87.977358l-47.546863 66.623963-15.292575 3.331842c-8.328531 1.967353-31.344629 7.116368-51.331388 11.658228-19.836581 4.544006-36.341362 8.178352-36.493644 7.873702-.30036-.300359-1.664849-12.113057-3.027192-26.195614-1.362344-14.232735-3.481957-34.069316-4.541861-44.212875l-2.121887-18.626562 10.298137-14.687565c5.601656-8.174062 17.564535-25.43828 26.345751-38.308672 21.351249-31.192304 68.593462-100.08827 75.257145-109.626821 2.874867-4.239356 8.326387-11.962878 11.810468-17.262137 6.056614-8.631058 6.813949-9.388306 9.388392-7.573279 1.512587 1.061985 12.565849 9.088012 24.528684 17.87133z"/><path d="m234.058679 474.542536c-24.680945 12.872537-24.226115 47.849367.90966 61.324854 6.056529 3.331756 6.964042 3.331756 104.479951 3.786586 67.683802.302505 100.540954-.15018 105.082815-1.212164 15.14454-3.784612 25.590604-16.047764 27.105273-31.797227 1.362343-14.082642-9.841055-30.43497-23.771286-34.524232-4.089176-1.362344-34.221641-1.817173-105.84444-1.817173h-99.9338l-8.023882 4.239356z"/></svg>

After

Width:  |  Height:  |  Size: 4.5 KiB

@@ -0,0 +1 @@
<svg height="200" viewBox="0 0 1024 1024" width="200" xmlns="http://www.w3.org/2000/svg"><path d="m152.811049 118.849443c-15.812621 4.297514-25.94171 8.595029-37.761527 16.269621-27.475706 17.807973-46.508803 47.276949-51.881211 80.58644-2.30433 13.967458-2.30433 541.697068 0 557.968835 5.67922 41.595562 29.471101 74.136949 66.61896 91.483631 22.410154 10.438047 25.939565 11.049525 85.956724 11.665295 36.379756.461291 56.180935.154479 61.555509-.922582 28.241728-6.292865 34.227782-42.824955 9.360986-57.099225-6.447344-3.683891-6.599677-3.683891-63.241903-4.451994l-56.792413-.768102-10.285714-5.063472c-12.585731-6.140532-22.871444-17.03987-27.321334-29.166455l-3.224702-8.595029-.152291-274.148373v-273.993894l3.529369-9.210799c4.297514-11.512961 15.655997-23.791901 27.323394-29.471121l8.595072-4.297515 263.864805-.46129 264.017224-.306791 9.515379 4.451972c12.894689 5.986053 21.182948 13.967436 27.016626 25.939564l5.063471 10.285714.768103 63.701048c.768103 69.687102.615813 67.84623 10.285714 77.057028 9.976755 9.515465 22.716965 11.204004 35.457175 4.913284 6.292865-3.072411 9.056319-5.835865 12.740209-11.974252l4.451994-7.829071-.461291-67.539418c-.459146-65.850879-.459146-67.84623-3.990703-78.284276-12.740209-38.527441-40.370459-66.310003-79.204669-79.357046l-10.744902-3.531557-270.15767-.306855c-258.797043-.306769-270.616816-.154414-280.900384 2.456685z"/><path d="m236.467754 301.818851c-6.754156 2.763454-13.81727 9.05632-17.192202 15.655997-7.829072 15.351331-1.843018 33.157158 13.967458 41.290896l8.290362 4.299659 154.418722-.306812 154.418723-.46129 5.833613-3.531557c7.520221-4.75666 12.740317-11.817628 15.040334-20.414803 3.686036-13.508312-4.295368-29.164309-17.803681-35.304842-5.833656-2.761308-14.428706-2.915787-159.638819-2.761308-97.162872 0-154.880013.613624-157.33451 1.53406z"/><path d="m696.194511 427.380076c-6.908635 3.224681-13.660603 9.363132-17.344536 16.271767-2.304309 3.990702-2.763454 11.972107-3.377078 54.337831l-.768103 49.733677-21.182863 4.297514c-75.061719 14.735561-137.074229 47.890573-188.496273 100.848908-45.436162 46.663325-77.209447 101.614866-98.08554 169.154284-7.213302 23.794026-7.520114 30.239225-2.147685 41.138562 4.297515 8.442695 11.972107 14.428749 21.642051 16.4241 7.522259 1.53406 20.10799-2.763454 28.705164-9.976756 16.117288-13.355979 60.632928-38.222774 92.251735-51.42213 47.738325-20.110135 110.67333-36.379756 157.643467-40.984083l4.297514-.461291.306898 53.724293c.461291 52.95619.461291 53.878772 3.990552 59.403535 10.59259 17.192203 30.852913 22.871444 46.665535 13.047021 3.06812-1.840872 23.330632-20.721614 45.279452-41.752186 26.169137-25.408973 52.41766-50.735686 78.745567-75.979967 124.179498-118.807069 118.193445-112.207434 118.193445-129.860885-.154479-16.576433.306812-16.117245-70.762017-79.663858-108.67798-97.165018-138.301435-123.720352-149.968918-134.465211-6.140533-5.679241-14.121894-11.819774-17.651392-13.508313-8.290276-3.990702-19.648759-4.143035-27.936975-.306812zm97.778642 144.748779c55.412832 49.581258 79.050234 70.455119 88.415511 78.284276 2.761308 2.302164 4.911138 4.604327 4.911138 5.372516 0 .613581-18.880742 19.341947-41.904519 41.290809-22.871444 22.103341-57.25585 55.106063-76.288925 73.373138-19.033075 18.264972-34.843551 33.155012-35.304842 33.155012s-.768103-15.810476-.768103-34.99803v-35.150363l-4.604326-7.367781c-6.599678-10.744772-17.192246-16.117287-31.775431-16.117287-11.972107 0-54.797062 5.831574-84.883954 11.665294-49.73359 9.669944-96.703727 24.098693-139.528683 42.979435-8.442695 3.838369-15.503663 6.447344-15.812621 6.140532-1.072769-.922582 18.880742-32.541302 29.166455-46.049701 5.063472-6.908635 17.958161-21.028426 28.550686-31.620908 38.988732-38.527484 79.51367-61.398929 133.697108-75.214053 16.117245-4.145181 26.862147-5.986097 57.101371-10.59038 13.660646-1.995351 22.564632-7.981405 27.93483-18.880742 3.840601-7.674593 3.990789-8.903922 3.990789-36.838902 0-15.812707.308957-28.857498.770248-28.857498.459145 0 25.787231 22.255675 56.333268 49.424633z"/><path d="m234.165591 463.453021c-22.719111 10.283568-23.794026 44.820307-1.688539 56.642226 6.292866 3.374932 6.445199 3.374932 110.671186 3.374932h104.380465l7.520114-3.683782c8.442781-4.145332 15.503663-13.660754 17.037724-23.178364 2.14983-12.278919-5.524763-26.094044-17.805827-32.389055-5.679242-2.761308-9.824423-2.915873-110.671186-2.915873-84.270329.154565-105.760047.461377-109.443937 2.149916z"/></svg>

After

Width:  |  Height:  |  Size: 4.3 KiB

+6 -5
View File
@@ -15,20 +15,21 @@ export type FixItDocumentEventMap = {
[K in keyof FixItEventMap]: CustomEvent<FixItEventMap[K]>
}
type Handler<T> = T extends void
/** Event handler type — infers the correct signature from the event payload. */
export type Handler<T> = T extends void
? (() => void) | ((event: CustomEvent<void>) => void)
: (event: CustomEvent<T>) => void
/** Typed event bus — wraps DOM CustomEvents with type-safe emit/on/off. */
export class TypedEventBus {
private target = document
#target = document
on<K extends keyof FixItEventMap>(event: K, handler: Handler<FixItEventMap[K]>): void {
this.target.addEventListener(event as string, handler as EventListener)
this.#target.addEventListener(event as string, handler as EventListener)
}
off<K extends keyof FixItEventMap>(event: K, handler: Handler<FixItEventMap[K]>): void {
this.target.removeEventListener(event as string, handler as EventListener)
this.#target.removeEventListener(event as string, handler as EventListener)
}
emit<K extends keyof FixItEventMap>(
@@ -36,7 +37,7 @@ export class TypedEventBus {
...args: FixItEventMap[K] extends void ? [] : [FixItEventMap[K]]
): void {
const detail = args[0]
this.target.dispatchEvent(
this.#target.dispatchEvent(
detail !== undefined
? new CustomEvent(event as string, { detail })
: new CustomEvent(event as string),
+1
View File
@@ -50,6 +50,7 @@ export class PublicAPI implements FixItPublicAPI {
get version() { return this.core.version }
get themeMode() { return this.core.themeMode }
get isDark() { return this.core.isDark }
get isRTL() { return this.core.isRTL }
setThemeMode(mode: string, persist?: boolean) {
this.theme.setThemeMode(mode, persist)
+2
View File
@@ -7,6 +7,7 @@ export interface CoreService {
readonly config: FixItConfig
readonly version: string
isDark: boolean
isRTL: boolean
themeMode: string
registerMaskOverlay: (name: string, handlers: MaskOverlayHandler) => void
openMaskOverlay: (name: string) => void
@@ -94,6 +95,7 @@ export interface FixItPublicAPI {
readonly version: string
readonly themeMode: string
readonly isDark: boolean
readonly isRTL: boolean
// Modules
readonly core: CoreService
readonly theme: ThemeService
+6 -2
View File
@@ -8,8 +8,8 @@
import { eventBus } from '../core/event-bus'
import { isDarkMode } from '../utils'
function applyJsonViewerTheme(isDark: boolean) {
document.querySelectorAll('json-viewer').forEach(($el: Element) => {
function applyJsonViewerTheme(isDark: boolean, scope: Element | Document = document) {
scope.querySelectorAll('json-viewer').forEach(($el: Element) => {
$el.setAttribute('theme', isDark ? 'dark' : 'light')
})
}
@@ -25,4 +25,8 @@ document.addEventListener('DOMContentLoaded', () => {
return
applyJsonViewerTheme(detail.isDark)
})
eventBus.on('fixit:content-decrypted', ({ detail }) => {
applyJsonViewerTheme(isDarkMode(), detail.target)
})
}, false)
+15 -11
View File
@@ -16,10 +16,13 @@ const copyText = createCopyText()
* - Re-initialize components after encrypted content is decrypted.
*/
export class ContentModule implements ContentService {
constructor(
private readonly core: CoreService,
private readonly code: CodeService,
) {}
#core: CoreService
#code: CodeService
constructor(core: CoreService, code: CodeService) {
this.#core = core
this.#code = code
}
/** Fetch and inline SVG icons referenced by `data-svg-src` attributes. */
initSVGIcon() {
@@ -131,7 +134,7 @@ export class ContentModule implements ContentService {
return
const footnoteMap = new Map<HTMLElement, HTMLElement>()
$footnoteRefs.forEach(($ref) => {
if (this.core.config.tooltip) {
if (this.#core.config.tooltip) {
const $link = $ref.querySelector<HTMLAnchorElement>('a.footnote-ref')
if ($link) {
$link.addEventListener('click', (e) => {
@@ -153,7 +156,7 @@ export class ContentModule implements ContentService {
if ($ref.hasAttribute('title'))
return
$ref.setAttribute('title', $content.textContent!.trim())
if (this.core.config.tooltip) {
if (this.#core.config.tooltip) {
CellTooltip.getOrCreateInstance($ref)
}
})
@@ -161,9 +164,10 @@ export class ContentModule implements ContentService {
/** Initialize CellTooltip on action buttons, copy buttons, and footnotes. */
initTooltip() {
if (!this.core.config.tooltip)
if (!this.#core.config.tooltip)
return
CellTooltip.initAll('li[data-task] > span[title]', { placement: 'right' })
const inlineEnd = this.#core.isRTL ? 'left' : 'right'
CellTooltip.initAll('li[data-task] > span[title]', { placement: inlineEnd })
CellTooltip.initAll('.action-btn[title]', { placement: 'bottom' })
CellTooltip.initAll('.copy-icon-btn[title]', { placement: 'top' })
CellTooltip.initAll('.fixit-encryptor-btn[title]')
@@ -177,9 +181,9 @@ export class ContentModule implements ContentService {
*/
initContent(target: Element | Document = document) {
this.initDetails(target)
this.code.initCodeWrapper()
this.code.initCodeTabs()
this.code.initDiagramCopyBtn()
this.#code.initCodeWrapper()
this.#code.initCodeTabs()
this.#code.initDiagramCopyBtn()
this.initTooltip()
this.initLinkGuardDialog(target)
}
+19 -17
View File
@@ -1,6 +1,6 @@
import type { CoreService } from '../core/tokens'
import type { FixItConfig, MaskOverlayHandler } from '../types'
import { getThemeMode, isDarkMode } from '../utils'
import { getThemeMode, isDarkMode, isRTL } from '../utils'
/**
* Core module — shared state initialization and mask overlay management.
@@ -13,15 +13,17 @@ import { getThemeMode, isDarkMode } from '../utils'
export class CoreModule implements CoreService {
readonly config: FixItConfig
readonly version: string
readonly isRTL: boolean
themeMode: string
isDark: boolean
private activeMaskOverlay: string | null = null
private readonly maskOverlays = new Map<string, MaskOverlayHandler>()
#activeMaskOverlay: string | null = null
#maskOverlays = new Map<string, MaskOverlayHandler>()
constructor() {
this.config = window.config
this.version = this.config.version
this.isRTL = isRTL()
this.themeMode = getThemeMode()
this.isDark = isDarkMode()
@@ -30,46 +32,46 @@ export class CoreModule implements CoreService {
/** Register a named mask overlay with open/close/isActive handlers. */
registerMaskOverlay(name: string, handlers: MaskOverlayHandler) {
this.maskOverlays.set(name, handlers)
this.#maskOverlays.set(name, handlers)
}
/** Toggle the mask element's blur class based on active overlay state. */
syncMaskState() {
document.getElementById('mask')?.classList.toggle('is-blur', Boolean(this.activeMaskOverlay))
document.getElementById('mask')?.classList.toggle('is-blur', Boolean(this.#activeMaskOverlay))
}
/** Open a named mask overlay, closing any previously active one. */
openMaskOverlay(name: string) {
const overlay = this.maskOverlays.get(name)
const overlay = this.#maskOverlays.get(name)
if (!overlay)
return
if (this.activeMaskOverlay && this.activeMaskOverlay !== name) {
this.closeMaskOverlay(this.activeMaskOverlay, true)
if (this.#activeMaskOverlay && this.#activeMaskOverlay !== name) {
this.closeMaskOverlay(this.#activeMaskOverlay, true)
}
overlay.onOpen?.()
this.activeMaskOverlay = name
this.#activeMaskOverlay = name
this.syncMaskState()
}
/** Close a named mask overlay and optionally skip mask state sync. */
closeMaskOverlay(name: string, skipSync = false) {
const overlay = this.maskOverlays.get(name)
const overlay = this.#maskOverlays.get(name)
if (!overlay)
return
overlay.onClose?.()
if (this.activeMaskOverlay === name) {
this.activeMaskOverlay = null
if (this.#activeMaskOverlay === name) {
this.#activeMaskOverlay = null
}
!skipSync && this.syncMaskState()
}
/** Toggle a named mask overlay open/closed. */
toggleMaskOverlay(name: string) {
const overlay = this.maskOverlays.get(name)
const overlay = this.#maskOverlays.get(name)
if (!overlay)
return
const isActive = overlay.isActive?.() ?? this.activeMaskOverlay === name
if (this.activeMaskOverlay === name && isActive) {
const isActive = overlay.isActive?.() ?? this.#activeMaskOverlay === name
if (this.#activeMaskOverlay === name && isActive) {
this.closeMaskOverlay(name)
return
}
@@ -78,10 +80,10 @@ export class CoreModule implements CoreService {
/** Close whichever mask overlay is currently active. */
closeActiveMaskOverlay() {
if (!this.activeMaskOverlay) {
if (!this.#activeMaskOverlay) {
this.syncMaskState()
return
}
this.closeMaskOverlay(this.activeMaskOverlay)
this.closeMaskOverlay(this.#activeMaskOverlay)
}
}
+7 -3
View File
@@ -7,14 +7,18 @@ import type { CoreService, EncryptionService } from '../core/tokens'
* - Initialize FixItDecryptor for full-page and shortcode-scoped decryption.
*/
export class EncryptionModule implements EncryptionService {
constructor(private readonly core: CoreService) {}
#core: CoreService
constructor(core: CoreService) {
this.#core = core
}
/** Initialize FixItDecryptor with encryption config. */
setup() {
if (!this.core.config.encryption || !window.FixItDecryptor)
if (!this.#core.config.encryption || !window.FixItDecryptor)
return
const decryptor = new window.FixItDecryptor()
decryptor.init(this.core.config.encryption)
decryptor.init(this.#core.config.encryption)
}
}
+11 -9
View File
@@ -15,11 +15,13 @@ export class EventsModule implements EventsService {
#resizeTimeout: number | null = null
#newScrollTop = 0
#oldScrollTop = 0
#core: CoreService
#code: CodeService
constructor(
private readonly core: CoreService,
private readonly code: CodeService,
) {}
constructor(core: CoreService, code: CodeService) {
this.#core = core
this.#code = code
}
/** Bind scroll listener: auto-hide headers, reading progress, back-to-top, and TOC sync. */
onScroll() {
@@ -40,7 +42,7 @@ export class EventsModule implements EventsService {
this.#newScrollTop = getScrollTop()
const scroll = this.#newScrollTop - this.#oldScrollTop
if (Math.abs(scroll) > ACCURACY) {
this.core.closeActiveMaskOverlay()
this.#core.closeActiveMaskOverlay()
const isScrollingDown = scroll > 0
$autoHeaders.forEach(($header) => {
if (isScrollingDown) {
@@ -97,7 +99,7 @@ export class EventsModule implements EventsService {
const _isMobile = isMobile()
if (_isMobile !== resizeBefore) {
this.core.closeActiveMaskOverlay()
this.#core.closeActiveMaskOverlay()
resizeBefore = _isMobile
}
}, 100)
@@ -110,7 +112,7 @@ export class EventsModule implements EventsService {
document.getElementById('mask')!.addEventListener('click', (e) => {
if (!(e.target as HTMLElement).classList.contains('is-blur'))
return
this.core.closeActiveMaskOverlay()
this.#core.closeActiveMaskOverlay()
}, false)
}
@@ -118,7 +120,7 @@ export class EventsModule implements EventsService {
initPrint() {
window.addEventListener('beforeprint', () => {
const $content = document.getElementById('content')!
const printConfig = this.core.config.print || {}
const printConfig = this.#core.config.print || {}
if (printConfig.expandAdmonition) {
$content.querySelectorAll('.admonition').forEach(($el: Element) => $el.classList.add('open'))
@@ -156,7 +158,7 @@ export class EventsModule implements EventsService {
}, false)
window.addEventListener('afterprint', () => {
this.code.initCodeTabs()
this.#code.initCodeTabs()
}, false)
}
+7 -3
View File
@@ -9,7 +9,11 @@ import type { CoreService, MenuService } from '../core/tokens'
* - Sync menu state with mask overlay.
*/
export class MenuModule implements MenuService {
constructor(private readonly core: CoreService) {}
#core: CoreService
constructor(core: CoreService) {
this.#core = core
}
/** Set min-width on desktop sub-menus to match parent item width. */
initDesktop() {
@@ -24,7 +28,7 @@ export class MenuModule implements MenuService {
const $menuMobile = document.getElementById('menu-mobile')
if (!$menuToggleMobile || !$menuMobile)
return
this.core.registerMaskOverlay('menu-mobile', {
this.#core.registerMaskOverlay('menu-mobile', {
isActive: () => $menuMobile.classList.contains('active'),
onOpen: () => {
$menuToggleMobile.classList.add('active')
@@ -38,7 +42,7 @@ export class MenuModule implements MenuService {
},
})
$menuToggleMobile.addEventListener('click', () => {
this.core.toggleMaskOverlay('menu-mobile')
this.#core.toggleMaskOverlay('menu-mobile')
}, false)
// add nested menu toggler
document.querySelectorAll<HTMLElement>('.menu-item>.nested-item').forEach(($nestedItem) => {
+17 -14
View File
@@ -13,17 +13,20 @@ import { getScrollTop, isMobile, isValidDate, scrollIntoView } from '../utils'
* - Initialize comment section UI and scroll-into-view.
*/
export class MiscModule implements MiscService {
private siteTime: ReturnType<typeof setInterval> | undefined
#siteTime: ReturnType<typeof setInterval> | undefined
#core: CoreService
constructor(private readonly core: CoreService) {}
constructor(core: CoreService) {
this.#core = core
}
/** Calculate and display the elapsed time since site launch. */
getSiteTime() {
const now = new Date()
const run = new Date(this.core.config.siteTime!)
const run = new Date(this.#core.config.siteTime!)
const $runTimes = document.querySelector<HTMLElement>('.run-times')
if (!isValidDate(run) || !$runTimes) {
clearInterval(this.siteTime)
clearInterval(this.#siteTime)
$runTimes && $runTimes.parentNode!.removeChild($runTimes)
return
}
@@ -38,20 +41,20 @@ export class MiscModule implements MiscService {
/** Start the site-time counter with visibility-change pausing. */
initSiteTime() {
if (this.core.config.siteTime) {
this.siteTime = setInterval(() => this.getSiteTime(), 500)
if (this.#core.config.siteTime) {
this.#siteTime = setInterval(() => this.getSiteTime(), 500)
document.addEventListener('visibilitychange', () => {
if (document.hidden) {
return clearInterval(this.siteTime)
return clearInterval(this.#siteTime)
}
this.siteTime = setInterval(() => this.getSiteTime(), 500)
this.#siteTime = setInterval(() => this.getSiteTime(), 500)
}, false)
}
}
/** Save and restore scroll position as an automatic bookmark. */
initAutoMark() {
if (!this.core.config.autoBookmark)
if (!this.#core.config.autoBookmark)
return
window.addEventListener('beforeunload', () => {
window.sessionStorage?.setItem(`fixit-bookmark/#${location.pathname}`, String(getScrollTop()))
@@ -89,7 +92,7 @@ export class MiscModule implements MiscService {
/** Initialize the comment section UI. */
initComment() {
if (!this.core.config.comment?.enable)
if (!this.#core.config.comment?.enable)
return
if (document.querySelector('#comments')) {
@@ -100,7 +103,7 @@ export class MiscModule implements MiscService {
}, false)
}
if (this.core.config.comment.expired)
if (this.#core.config.comment.expired)
document.querySelector('#comments')!.remove()
}
@@ -109,8 +112,8 @@ export class MiscModule implements MiscService {
*/
initPostChat() {
const initThemeCompatibility = () => {
if (this.core.config.postChat) {
document.body.classList.toggle('dark', this.core.isDark)
if (this.#core.config.postChat) {
document.body.classList.toggle('dark', this.#core.isDark)
eventBus.on('fixit:switch-theme', ({ detail }) => {
if (!detail.isChanged)
return
@@ -122,7 +125,7 @@ export class MiscModule implements MiscService {
const initPostChatUser = () => {
if (!window.postChatUser || !window.postChatConfig || window.postChatConfig.userMode === 'magic')
return
window.postChat_theme = this.core.isDark ? 'dark' : 'light'
window.postChat_theme = this.#core.isDark ? 'dark' : 'light'
eventBus.on('fixit:switch-theme', ({ detail }) => {
if (!detail.isChanged)
return
+8 -4
View File
@@ -10,11 +10,15 @@ import { eventBus } from '../core/event-bus'
* - Show update notification toast and handle refresh.
*/
export class PWAModule implements PWAService {
constructor(private readonly core: CoreService) {}
#core: CoreService
constructor(core: CoreService) {
this.#core = core
}
/** Register the service worker with update detection and notification binding. */
async setup() {
const pwa = this.core.config.PWA
const pwa = this.#core.config.PWA
if (!pwa?.enable || !('serviceWorker' in navigator))
return
@@ -49,14 +53,14 @@ export class PWAModule implements PWAService {
window.location.reload()
})
this.bindUpdateNotification(registration)
this.#bindUpdateNotification(registration)
}
/**
* Bind the template-rendered update notification toast.
* Shows the toast on `fixit:sw-update` and wires the refresh button to skip waiting.
*/
private bindUpdateNotification(registration: ServiceWorkerRegistration) {
#bindUpdateNotification(registration: ServiceWorkerRegistration) {
const toast = document.querySelector<HTMLElement>('.sw-update-notification')
if (!toast)
return
+9 -6
View File
@@ -19,8 +19,11 @@ export class SearchModule implements SearchService {
#openDialog: (() => void) | undefined
#closeDialog: (() => void) | undefined
#initialized = false
#core: CoreService
constructor(private readonly core: CoreService) {}
constructor(core: CoreService) {
this.#core = core
}
/** Create the appropriate search engine based on type. */
#createEngine(type: string, searchConfig: SearchConfig): SearchEngine {
@@ -30,9 +33,9 @@ export class SearchModule implements SearchService {
case 'fuse':
return createFuseEngine(searchConfig)
case 'cse':
return createCSEEngine(this.core.config.cse)
return createCSEEngine(this.#core.config.cse)
case 'pagefind':
return createPagefindEngine(searchConfig, this.core.config.pagefind!)
return createPagefindEngine(searchConfig, this.#core.config.pagefind!)
default:
console.warn(`[FixIt] Unknown search type: "${type}". Supported types: algolia, fuse, cse, pagefind.`)
return {
@@ -45,7 +48,7 @@ export class SearchModule implements SearchService {
/** Initialize @algolia/autocomplete-js instance. */
#initAutosearch() {
const searchConfig = this.core.config.search
const searchConfig = this.#core.config.search
if (!searchConfig || !this.#engine)
return
@@ -218,7 +221,7 @@ export class SearchModule implements SearchService {
document.querySelector('.search-trigger.desktop')?.addEventListener('click', open)
document.querySelector('.search-trigger.mobile')?.addEventListener('click', () => {
this.core.closeMaskOverlay('menu-mobile')
this.#core.closeMaskOverlay('menu-mobile')
open()
})
@@ -247,7 +250,7 @@ export class SearchModule implements SearchService {
/** Initialize the search overlay, autocomplete, and engine-specific logic. */
setup() {
const searchConfig = this.core.config.search
const searchConfig = this.#core.config.search
if (!searchConfig || !searchConfig.type)
return
+18 -15
View File
@@ -10,9 +10,12 @@ import { eventBus } from '../core/event-bus'
* - Persist user preference to localStorage.
*/
export class ThemeModule implements ThemeService {
private readonly mql = window.matchMedia('(prefers-color-scheme: dark)')
#mql = window.matchMedia('(prefers-color-scheme: dark)')
#core: CoreService
constructor(private readonly core: CoreService) {}
constructor(core: CoreService) {
this.#core = core
}
/**
* Apply a theme mode and emit the `fixit:switch-theme` event.
@@ -20,19 +23,19 @@ export class ThemeModule implements ThemeService {
* @param persist - Whether to save the choice to localStorage (default: `true`).
*/
setThemeMode(mode: string, persist = true) {
const prevIsDark = this.core.isDark
this.core.themeMode = mode
const prevIsDark = this.#core.isDark
this.#core.themeMode = mode
document.documentElement.dataset.themeMode = mode
this.core.isDark = mode === 'auto' ? this.mql.matches : mode === 'dark'
this.#core.isDark = mode === 'auto' ? this.#mql.matches : mode === 'dark'
if (persist) {
window.localStorage?.setItem('theme-mode', mode)
}
eventBus.emit('fixit:switch-theme', {
isDark: this.core.isDark,
isDark: this.#core.isDark,
mode,
isChanged: prevIsDark !== this.core.isDark,
isChanged: prevIsDark !== this.#core.isDark,
})
}
@@ -49,7 +52,7 @@ export class ThemeModule implements ThemeService {
return
applyThemeColor(detail.isDark)
})
applyThemeColor(this.core.isDark)
applyThemeColor(this.#core.isDark)
}
/** Initialize the theme switch button cycle and system preference listener. */
@@ -58,21 +61,21 @@ export class ThemeModule implements ThemeService {
document.querySelectorAll('.theme-switch').forEach(($themeSwitch: Element) => {
$themeSwitch.addEventListener('click', () => {
const currentIndex = modes.indexOf(this.core.themeMode as typeof modes[number])
const currentIndex = modes.indexOf(this.#core.themeMode as typeof modes[number])
const nextMode = modes[(currentIndex + 1) % modes.length]
this.setThemeMode(nextMode)
}, false)
})
this.mql.addEventListener('change', (e: MediaQueryListEvent) => {
if (this.core.themeMode !== 'auto')
this.#mql.addEventListener('change', (e: MediaQueryListEvent) => {
if (this.#core.themeMode !== 'auto')
return
const prevIsDark = this.core.isDark
this.core.isDark = e.matches
const prevIsDark = this.#core.isDark
this.#core.isDark = e.matches
eventBus.emit('fixit:switch-theme', {
isDark: this.core.isDark,
isDark: this.#core.isDark,
mode: 'auto',
isChanged: prevIsDark !== this.core.isDark,
isChanged: prevIsDark !== this.#core.isDark,
})
})
}
+120 -78
View File
@@ -16,7 +16,11 @@ const TOC_CONTAINER_IDS = ['toc-content-auto', 'toc-content-static', 'toc-conten
* - Clone TOC nodes to detach APlayer event listeners.
*/
export class TocModule implements TocService {
private activeTocId: string | null = null
#activeTocId: string | null = null
#previousActiveLinks = new Map<HTMLElement, HTMLAnchorElement | null>()
#headingOffsets: Array<{ id: string, top: number }> = []
#headingOffsetsDirty = true
#rafId: number | null = null
/** Get all TOC content containers (auto, static, and drawer). */
#getTocContainers(): HTMLElement[] {
@@ -25,38 +29,55 @@ export class TocModule implements TocService {
.filter(Boolean) as HTMLElement[]
}
/** Compute the scroll offset for header + breadcrumb. */
#getIndexOffset(): number {
const headerId = isMobile() ? 'header-mobile' : 'header-desktop'
const $header = document.getElementById(headerId)
const headerMode = document.body.getAttribute(`data-${headerId}`)
if (!$header || window.getComputedStyle($header).display === 'none')
return 20
const shouldApplyOffset = headerMode === 'sticky' || (headerMode === 'auto' && !$header.classList.contains('header__fadeOutUp'))
const headerOffset = shouldApplyOffset ? $header.offsetHeight : 0
const breadcrumbOffset = document.querySelector<HTMLElement>('.breadcrumb-container')?.offsetHeight || 0
return 20 + headerOffset + breadcrumbOffset
}
/** Cache heading absolute offsets for binary search. Called on init/resize/content change. */
#cacheHeadingOffsets() {
const $headingElements = document.querySelectorAll<HTMLElement>('.heading-element[id]')
this.#headingOffsets = Array.from($headingElements).map($h => ({
id: $h.id,
top: window.scrollY + $h.getBoundingClientRect().top,
}))
this.#headingOffsetsDirty = false
}
/**
* Determine which heading is currently active based on scroll position.
* Uses cached offsets with binary search for O(log n) performance.
* @returns The active heading element, or `null` if none found.
*/
#getActiveTocHeading(): HTMLElement | null {
const $headingElements = Array.from(document.querySelectorAll<HTMLElement>('.heading-element[id]'))
if (!$headingElements.length)
if (this.#headingOffsetsDirty || !this.#headingOffsets.length)
this.#cacheHeadingOffsets()
if (!this.#headingOffsets.length)
return null
const headerOffset = (() => {
const headerId = isMobile() ? 'header-mobile' : 'header-desktop'
const $header = document.getElementById(headerId)
const headerMode = document.body.getAttribute(`data-${headerId}`)
if (!$header || window.getComputedStyle($header).display === 'none')
return 0
const shouldApplyOffset = headerMode === 'sticky' || (headerMode === 'auto' && !$header.classList.contains('header__fadeOutUp'))
return shouldApplyOffset ? $header.offsetHeight : 0
})()
const breadcrumbOffset = document.querySelector<HTMLElement>('.breadcrumb-container')?.offsetHeight || 0
const indexOffset = 20 + headerOffset + breadcrumbOffset
const threshold = window.scrollY + indexOffset + 1
let $activeHeading = $headingElements[0]
for (const $heading of $headingElements) {
const headingTop = window.scrollY + $heading.getBoundingClientRect().top
if (headingTop <= threshold) {
$activeHeading = $heading
const threshold = window.scrollY + this.#getIndexOffset() + 1
let lo = 0
let hi = this.#headingOffsets.length - 1
let result = 0
while (lo <= hi) {
const mid = (lo + hi) >>> 1
if (this.#headingOffsets[mid].top <= threshold) {
result = mid
lo = mid + 1
}
else {
break
hi = mid - 1
}
}
return $activeHeading
return document.getElementById(this.#headingOffsets[result].id)
}
/**
@@ -73,50 +94,64 @@ export class TocModule implements TocService {
}
/**
* Highlight the active TOC item and its parent chain.
* Get the ancestor `<li>` chain from a link up to the TOC root.
* @param $link - The anchor element inside a `<li>`.
* @returns An array of ancestor `<li>` elements (nearest first).
*/
#getAncestorChain($link: Element): HTMLLIElement[] {
const chain: HTMLLIElement[] = []
let $parent = $link.closest('li')
while ($parent) {
chain.push($parent)
$parent = $parent.parentElement?.closest('li') || null
}
return chain
}
/**
* Highlight the active TOC item and its parent chain using diff-based updates.
* Only removes/adds classes on the difference between old and new active chains,
* avoiding a global clear that causes visual flash.
* @param $tocRoot - The TOC root container element.
* @param activeId - The id of the currently active heading.
*/
#applyTocActiveState($tocRoot: HTMLElement, activeId: string) {
if (!$tocRoot)
return
$tocRoot.querySelectorAll('a[href^="#"]').forEach(($tocLink: Element) => {
$tocLink.classList.remove('active')
})
$tocRoot.querySelectorAll('li').forEach(($tocLi: Element) => {
$tocLi.classList.remove('has-active')
})
const $activeLink = this.#getTocLinkById($tocRoot, activeId)
if (!$activeLink)
const $newActiveLink = this.#getTocLinkById($tocRoot, activeId)
const $prevActiveLink = this.#previousActiveLinks.get($tocRoot) || null
if ($newActiveLink === $prevActiveLink)
return
$activeLink.classList.add('active')
let $parent = $activeLink.closest('li')
while ($parent) {
$parent.classList.add('has-active')
$parent = $parent.parentElement?.closest('li') || null
// Remove from old chain
if ($prevActiveLink) {
$prevActiveLink.classList.remove('active')
for (const $li of this.#getAncestorChain($prevActiveLink)) {
$li.classList.remove('has-active')
}
}
// Add to new chain
if ($newActiveLink) {
$newActiveLink.classList.add('active')
for (const $li of this.#getAncestorChain($newActiveLink)) {
$li.classList.add('has-active')
}
}
this.#previousActiveLinks.set($tocRoot, $newActiveLink)
}
/**
* Scroll the active TOC link into the visible area of its container.
* @param $tocRoot - The TOC root container element.
* @param activeId - The id of the currently active heading.
* @param $scrollContainer - The scrollable container (defaults to `$tocRoot`).
*/
#scrollActiveTocLinkIntoView($tocRoot: HTMLElement, activeId: string, $scrollContainer: HTMLElement = $tocRoot) {
#scrollActiveTocLinkIntoView($tocRoot: HTMLElement, activeId: string) {
const $activeLink = this.#getTocLinkById($tocRoot, activeId)
if (!$activeLink || !$scrollContainer)
if (!$activeLink)
return
const containerRect = $scrollContainer.getBoundingClientRect()
const linkRect = $activeLink.getBoundingClientRect()
const offsetTop = linkRect.top - containerRect.top
const offsetBottom = linkRect.bottom - containerRect.bottom
if (offsetTop < 0) {
$scrollContainer.scrollTop += offsetTop
}
else if (offsetBottom > 0) {
$scrollContainer.scrollTop += offsetBottom
}
$activeLink.scrollIntoView({ behavior: 'smooth', block: 'nearest' })
}
/** Update the TOC container's max-height CSS variable to fit the viewport. */
@@ -129,38 +164,44 @@ export class TocModule implements TocService {
}
}
/** Sync the active heading highlight across all TOC containers. */
/** Sync the active heading highlight across all TOC containers. Throttled via rAF. */
syncTocActiveState() {
const $activeHeading = this.#getActiveTocHeading()
if (!$activeHeading?.id)
if (this.#rafId !== null)
return
const activeId = $activeHeading.id
const $tocRoots = this.#getTocContainers()
.map($container => $container.querySelector<HTMLElement>('nav'))
.filter(Boolean) as HTMLElement[]
$tocRoots.forEach(($tocRoot) => {
this.#applyTocActiveState($tocRoot, activeId)
})
if (this.activeTocId !== activeId) {
this.activeTocId = activeId
if (!isTocStatic()) {
const $autoTocRoot = document.querySelector<HTMLElement>('#toc-content-auto > nav')
const $autoTocContainer = document.getElementById('toc-content-auto')
if ($autoTocRoot && $autoTocContainer) {
this.#scrollActiveTocLinkIntoView($autoTocRoot, activeId, $autoTocContainer)
this.#rafId = requestAnimationFrame(() => {
this.#rafId = null
const $activeHeading = this.#getActiveTocHeading()
if (!$activeHeading?.id)
return
const activeId = $activeHeading.id
const $tocRoots = this.#getTocContainers()
.map($container => $container.querySelector<HTMLElement>('nav'))
.filter(Boolean) as HTMLElement[]
$tocRoots.forEach(($tocRoot) => {
this.#applyTocActiveState($tocRoot, activeId)
})
if (this.#activeTocId !== activeId) {
this.#activeTocId = activeId
if (!isTocStatic()) {
const $autoTocRoot = document.querySelector<HTMLElement>('#toc-content-auto > nav')
if ($autoTocRoot) {
this.#scrollActiveTocLinkIntoView($autoTocRoot, activeId)
}
}
if ((document.getElementById('nav-dialog') as HTMLDialogElement)?.open) {
const $dialogTocRoot = document.querySelector<HTMLElement>('#toc-content-drawer > nav')!
this.#scrollActiveTocLinkIntoView($dialogTocRoot, activeId)
}
}
if ((document.getElementById('toc-dialog') as HTMLDialogElement)?.open) {
const $dialogTocRoot = document.querySelector<HTMLElement>('#toc-content-drawer > nav')!
this.#scrollActiveTocLinkIntoView($dialogTocRoot, activeId, $dialogTocRoot)
}
}
})
}
/** Sync TOC layout state: drawer button visibility, height, and active heading. */
#syncTocLayout() {
document.querySelector<HTMLElement>('#toc-drawer-button')?.classList.toggle('hidden', !isTocStatic())
this.activeTocId = null
document.querySelector<HTMLElement>('#nav-drawer-button')?.classList.toggle('hidden', !isTocStatic())
this.#activeTocId = null
this.#previousActiveLinks.clear()
this.#headingOffsetsDirty = true
this.syncTocHeight()
this.syncTocActiveState()
}
@@ -179,6 +220,7 @@ export class TocModule implements TocService {
$clone.removeAttribute('id')
$container.appendChild($clone)
}
this.#headingOffsetsDirty = true
}
/** Bind the `toc-auto` title click handler for show/hide toggle. */
@@ -204,7 +246,7 @@ export class TocModule implements TocService {
/** Initialize the mobile TOC drawer dialog and its open/close handlers. */
#initTocDrawerLinkClose() {
const dialog = document.querySelector<HTMLDialogElement>('#toc-dialog')
const dialog = document.querySelector<HTMLDialogElement>('#nav-dialog')
if (!dialog)
return
document.querySelectorAll<HTMLAnchorElement>('#toc-content-drawer a[href^="#"]').forEach(($link) => {
@@ -217,11 +259,11 @@ export class TocModule implements TocService {
/** Initialize the mobile TOC drawer dialog and its open/close handlers. */
#initTocDrawer() {
const dialog = document.querySelector<HTMLDialogElement>('#toc-dialog')
const openButton = document.querySelector<HTMLElement>('#toc-drawer-button')
const dialog = document.querySelector<HTMLDialogElement>('#nav-dialog')
const openButton = document.querySelector<HTMLElement>('#nav-drawer-button')
if (!dialog || !openButton)
return
const closeButton = dialog.querySelector<HTMLElement>('.toc-close-btn')
const closeButton = dialog.querySelector<HTMLElement>('.nav-close-btn')
closeButton?.addEventListener('click', () => dialog.close())
openButton.addEventListener('click', () => {
dialog.showModal()
@@ -229,7 +271,7 @@ export class TocModule implements TocService {
this.syncTocHeight()
this.syncTocActiveState()
const $dialogTocRoot = document.querySelector<HTMLElement>('#toc-content-drawer > nav')!
this.#scrollActiveTocLinkIntoView($dialogTocRoot, this.activeTocId!, $dialogTocRoot)
this.#scrollActiveTocLinkIntoView($dialogTocRoot, this.#activeTocId!)
;(document.activeElement as HTMLElement)?.blur()
})
dialog.addEventListener('close', () => {
+8
View File
@@ -1,3 +1,11 @@
/**
* Check whether the document direction is right-to-left.
* @returns `true` if the document is RTL.
*/
export function isRTL(): boolean {
return document.documentElement.dir === 'rtl'
}
/**
* Get the current vertical scroll position.
* @returns The scroll offset in pixels.
File diff suppressed because one or more lines are too long
+8
View File
@@ -8,6 +8,14 @@
@forward "hugo:vars";
@forward "hugo:vars/internal";
/// CSS variable prefix for all custom properties.
/// @type String
$prefix: fi- !default;
/// Root prefix for CSS custom properties (derived from $prefix).
/// @type String
$rootPrefix: --#{$prefix} !default;
/// Default header height.
/// @type Length
$header-height: 3.5rem !default;
+1 -1
View File
@@ -7,7 +7,7 @@
padding: 0.5rem 1rem;
margin-block: 1rem;
color: inherit;
border-left: 0.25em solid fi-var(alert-border-color);
border-inline-start: 0.25em solid fi-var(alert-border-color);
> :first-child {
margin-top: 0;
+18 -8
View File
@@ -22,13 +22,13 @@
display: inline-block;
width: fi-var(color-code-size);
height: fi-var(color-code-size);
@include border-radius(full);
margin-right: 0.25em;
margin-inline-end: 0.25em;
vertical-align: middle;
border: 1px solid;
pointer-events: none;
translate: 0 -1px;
border-color: light-dark(#d1d9e0b3, #3d444db3);
@include border-radius(full);
}
}
@@ -42,6 +42,7 @@
font-family: fi-var(code-font-family);
background-color: fi-var(code-block-background-color);
tab-size: 4;
direction: ltr;
@include border-radius;
+ pre {
@@ -91,6 +92,7 @@
.highlight {
margin: 0.5rem 0;
position: relative;
direction: ltr;
@include border-radius;
// lineNumbersInTable=true
@@ -161,7 +163,7 @@
&:not(.code-block) {
.lntd:last-child pre.chroma {
padding-left: 0;
padding-inline-start: 0;
}
}
@@ -224,6 +226,10 @@
@include border-radius(top);
@include sticky-top-offset;
[dir="rtl"] & {
direction: rtl;
}
+ .code-wrapper {
@include border-radius(bottom);
@@ -237,7 +243,7 @@
padding: 0.4rem;
&::after {
padding-left: 0.2rem;
padding-inline-start: 0.2rem;
content: attr(data-name, fi-var(code-type, 'Code'));
}
@@ -366,7 +372,7 @@
.copy-icon-btn {
position: absolute;
top: 0.5rem;
right: 0.5rem;
inset-inline-end: 0.5rem;
}
// classic mode code block collapsed
@@ -483,7 +489,7 @@
counter-increment: codeNos;
content: counter(codeNos);
white-space: nowrap;
text-align: right;
text-align: end;
width: calc(#{fi-var(line-digit)} * 1ch);
min-width: 0.75rem;
padding-inline: 0.75rem;
@@ -509,7 +515,7 @@
&:not(.line-nos-hidden) {
.lntd:last-child pre.chroma:not([contenteditable='true']),
.code-wrapper > pre.chroma:not(:has(.ln)) {
padding-left: 0;
padding-inline-start: 0;
}
}
@@ -616,7 +622,7 @@
&:not(:last-child)::after {
content: '';
position: absolute;
right: 0;
inset-inline-end: 0;
top: 50%;
translate: 0 -50%;
width: 1px;
@@ -653,6 +659,10 @@
pointer-events: none;
transition: 0.3s ease-in-out;
@include border-radius;
[dir="rtl"] & {
translate: -2px 2px;
}
}
}
+70 -14
View File
@@ -15,14 +15,14 @@
display: inline-block;
width: max-content;
rotate: 30deg;
margin-right: 0.25em;
margin-inline-end: 0.25em;
color: fi-var(danger);
}
.icon-repost {
display: inline-block;
width: max-content;
margin-right: 0.25em;
margin-inline-end: 0.25em;
color: fi-var(success);
}
@@ -116,27 +116,76 @@
text-rendering: auto;
-webkit-font-smoothing: antialiased;
position: absolute;
left: 5%;
inset-inline-start: 5%;
top: 50%;
translate: 0 -50%;
color: fi-var(hr-active-color);
font-size: 20px;
line-height: 1;
transition: left 1s ease-in-out, color 0.3s ease, border-color 0.3s ease;
transition: inset-inline-start 1s ease-in-out, color 0.3s ease, border-color 0.3s ease;
font-family: var(--fa-family-classic);
font-weight: 600;
content: '\f0c4';
@include z-index(base);
[dir="rtl"] & {
scale: -1 1;
}
}
&:hover::before {
left: calc(95% - 20px);
inset-inline-start: calc(95% - 20px);
}
}
}
.content {
margin-block: 1rem;
counter-reset: h2 h3 h4 h5 h6;
> h2.heading-element {
counter-increment: h2;
counter-reset: h3 h4 h5 h6;
}
> h3.heading-element {
counter-increment: h3;
counter-reset: h4 h5 h6;
}
> h4.heading-element {
counter-increment: h4;
counter-reset: h5 h6;
}
> h5.heading-element {
counter-increment: h5;
counter-reset: h6;
}
> h6.heading-element {
counter-increment: h6;
}
> h2.heading-element .heading-numbered::before {
content: counter(h2) ". ";
}
> h3.heading-element .heading-numbered::before {
content: counter(h2) "." counter(h3) ". ";
}
> h4.heading-element .heading-numbered::before {
content: counter(h2) "." counter(h3) "." counter(h4) ". ";
}
> h5.heading-element .heading-numbered::before {
content: counter(h2) "." counter(h3) "." counter(h4) "." counter(h5) ". ";
}
> h6.heading-element .heading-numbered::before {
content: counter(h2) "." counter(h3) "." counter(h4) "." counter(h5) "." counter(h6) ". ";
}
> h1,
> h2 {
@@ -217,7 +266,7 @@
}
:is(ol, ul) :is(ol, ul) {
padding-left: 20px;
padding-inline-start: 20px;
}
li::marker {
@@ -232,7 +281,8 @@
&[data-task] {
list-style: none;
@include task-icon {
margin: 0 0.25em 0 -1.5em;
margin-block: 0;
margin-inline: -1.5em 0.25em;
color: fi-var(task-icon-color, fi-var(secondary));
};
@include task-text {
@@ -343,12 +393,12 @@
th,
td {
padding: 0.3rem 1rem;
border-right: 1px solid fi-var(table-border-color);
border-inline-end: 1px solid fi-var(table-border-color);
border-bottom: 1px solid fi-var(table-border-color);
}
tr > :last-child {
border-right: none;
border-inline-end: none;
}
> :last-child > tr:last-child > * {
@@ -392,14 +442,14 @@
blockquote {
display: block;
border-left: 0.25em solid fi-var(global-border-color);
border-inline-start: 0.25em solid fi-var(global-border-color);
color: fi-var(blockquote-color);
padding: 0 1em;
margin: 1rem 0;
ul,
ol {
padding-left: 1.5em;
padding-inline-start: 1.5em;
}
dl dd {
@@ -427,7 +477,7 @@
ol {
margin-block: 1em;
padding-left: 1rem;
padding-inline-start: 1rem;
}
hr {
@@ -465,6 +515,7 @@
.diagram-container {
position: relative;
margin-block: 0.5rem;
direction: ltr;
> .copy-icon-btn {
position: absolute;
@@ -480,12 +531,17 @@
overflow-y: hidden;
// neutralize the margin-right setting of .katex .vlist-t2
// to prevent scrollbars from appearing when the width is not full
padding-right: 2px;
padding-inline-end: 2px;
}
.katex {
display: inline-block;
direction: ltr;
}
.katex-error {
padding: 0.14em 0.28em;
background-color: mark;
cursor: help;
direction: ltr;
@include border-radius;
}
@@ -526,7 +582,7 @@
&.special {
.single-title,
.single-subtitle {
text-align: right;
text-align: end;
}
}
}
+5 -3
View File
@@ -165,8 +165,9 @@ article fixit-encryptor {
.fixit-decryptor-field {
flex: 1;
height: 2.5rem;
border-right: none;
border-radius: fi-var(global-border-radius) 0 0 fi-var(global-border-radius);
border-inline-end: none;
@include border-radius(start);
@include border-radius(end, 0);
&:focus-within + .fixit-decryptor-btn {
border-color: var(--fi-primary);
@@ -177,8 +178,9 @@ article fixit-encryptor {
.fixit-decryptor-btn {
width: auto;
padding: 0 0.85rem;
border-radius: 0 fi-var(global-border-radius) fi-var(global-border-radius) 0;
transition: border-color 0.2s ease, box-shadow 0.2s ease;
@include border-radius(start, 0);
@include border-radius(end);
}
&.decrypted > .fixit-decryptor-container {
+1 -1
View File
@@ -1,6 +1,6 @@
@forward "content";
@forward "shortcodes";
@forward "alert";
@forward "code";
@forward "content";
@forward "fixit-decryptor";
@forward "patch";
@@ -8,10 +8,10 @@
position: relative;
margin: 1rem 0;
padding: 0 0.75rem;
border-left: .25rem solid;
border-inline-start: .25rem solid;
overflow: hidden;
background-color: fi-var(admonition-bg-color);
border-left-color: fi-var(admonition-color);
border-inline-start-color: fi-var(admonition-color);
@include border-radius;
.admonition-title {
@@ -30,11 +30,12 @@
// title-only admonition without content
&:not(:has(+ .details-content)) {
@include set-fi-var(admonition-title-font-weight, normal);
padding: 0.75rem 1rem 0.75rem 2.2rem;
padding-inline: 2.2rem 1rem;
padding-block: 0.75rem;
border: 0;
i.icon {
left: 1.1rem;
inset-inline-start: 1.1rem;
font-size: 1rem;
}
}
@@ -73,15 +74,23 @@
font-size: 0.85rem;
position: absolute;
top: 50%;
left: 0.9rem;
inset-inline-start: 0.9rem;
translate: -50% -50%;
[dir="rtl"] & {
translate: 50% -50%;
}
}
i.details-icon {
position: absolute;
top: 50%;
right: 0.9rem;
inset-inline-end: 0.9rem;
translate: 50% -50%;
[dir="rtl"] & {
translate: -50% -50%;
}
}
// set color for each admonition type
@@ -20,8 +20,8 @@
position: absolute;
top: 0.75rem;
bottom: 0.75rem;
left: 0;
right: 0;
inset-inline-start: 0;
inset-inline-end: 0;
background-image: fi-var(logo-img);
background-repeat: no-repeat;
filter: blur(0.5rem);
@@ -67,20 +67,22 @@
width: 1rem;
height: 1rem;
flex-shrink: 0;
margin-right: 0.25rem;
margin-inline-end: 0.25rem;
}
&url {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
// URL direction should stay LTR
direction: ltr;
}
&shortcut-icon {
width: 4rem;
height: 4rem;
flex-shrink: 0;
margin-left: 0.25rem;
margin-inline-start: 0.25rem;
&:is(i) {
text-align: center;
@@ -95,7 +97,7 @@
width: 4rem;
height: 4rem !important;
flex-shrink: 0;
margin-left: 0.25rem;
margin-inline-start: 0.25rem;
object-fit: cover;
@include border-radius(full);
}
@@ -1,7 +1,7 @@
@use "core/functions" as *;
.single blockquote.blockquote-center {
border-left: none;
border-inline-start: none;
margin: 40px 0;
padding: 0;
position: relative;
@@ -10,7 +10,7 @@
&::after,
&::before {
left: 0;
inset-inline-start: 0;
line-height: 1;
opacity: 0.6;
position: absolute;
@@ -19,19 +19,27 @@
&::before {
border-top: 1px solid fi-var(global-border-color);
text-align: left;
text-align: start;
top: -20px;
font-family: var(--fa-family-classic);
font-weight: 900;
content: '\f10d';
[dir="rtl"] & {
content: '\f10e';
}
}
&::after {
border-bottom: 1px solid fi-var(global-border-color);
bottom: -20px;
text-align: right;
text-align: end;
font-family: var(--fa-family-classic);
font-weight: 900;
content: '\f10e';
[dir="rtl"] & {
content: '\f10d';
}
}
}
+1 -1
View File
@@ -12,7 +12,7 @@
position: absolute;
width: 100%;
height: 100%;
left: 0;
inset-inline-start: 0;
top: 0;
}
@@ -8,6 +8,7 @@
line-height: 1;
margin-block: 0.5rem;
transition: box-shadow 0.2s ease;
direction: ltr;
@include border-radius;
&:hover {
+6 -2
View File
@@ -18,7 +18,7 @@
svg {
max-width: 100%;
height: auto;
height: auto;
}
}
@@ -60,12 +60,16 @@
&::before {
content: '';
position: absolute;
left: 0;
inset-inline-start: 0;
top: 50%;
width: 1px;
translate: -2px -50%;
height: fi-var(code-block-font-size);
background-color: fi-var(global-border-color-weight);
[dir="rtl"] & {
translate: 2px -50%;
}
}
}
+69 -35
View File
@@ -73,8 +73,8 @@ tab-container {
}
}
&[placement='left'],
&[placement='right'] {
&[placement='start'],
&[placement='end'] {
max-width: 100%;
&::part(tablist-wrapper) {
@@ -103,7 +103,7 @@ tab-container {
flex-direction: column-reverse;
}
&[placement='right'] {
&[placement='end'] {
flex-direction: row-reverse;
}
@@ -166,8 +166,8 @@ tab-container {
}
}
&[placement='left'],
&[placement='right'] {
&[placement='start'],
&[placement='end'] {
> .tab-button {
@include tab-button-size(1rem, 0);
}
@@ -202,34 +202,44 @@ tab-container {
}
// Left placement
&[placement='left'] {
&[placement='start'] {
&::part(tablist-tab-wrapper) {
border-right: 2px solid fi-var(global-border-color);
border-inline-end: 2px solid fi-var(global-border-color);
}
&::part(tablist-wrapper)::before {
box-shadow: inset -2px 0 0 fi-var(primary);
translate: 2px 0;
[dir="rtl"] & {
box-shadow: inset 2px 0 0 fi-var(primary);
translate: -2px 0;
}
}
> .tab-button {
text-align: right;
text-align: end;
}
}
// Right placement
&[placement='right'] {
&[placement='end'] {
&::part(tablist-tab-wrapper) {
border-left: 2px solid fi-var(global-border-color);
border-inline-start: 2px solid fi-var(global-border-color);
}
&::part(tablist-wrapper)::before {
box-shadow: inset 2px 0 0 fi-var(primary);
translate: -2px 0;
[dir="rtl"] & {
box-shadow: inset -2px 0 0 fi-var(primary);
translate: 2px 0;
}
}
> .tab-button {
text-align: left;
text-align: start;
}
}
}
@@ -268,8 +278,8 @@ tab-container {
}
}
&[placement='left'],
&[placement='right'] {
&[placement='start'],
&[placement='end'] {
padding-bottom: 0.5rem;
&::part(tablist) {
@@ -296,27 +306,35 @@ tab-container {
}
// Left placement
&[placement='left'] {
&[placement='start'] {
&::part(tablist) {
margin-left: 0.5rem;
margin-inline-end: 0.5rem;
}
> .tab-button {
&:hover {
translate: 2px 0;
[dir="rtl"] & {
translate: -2px 0;
}
}
}
}
// Right placement
&[placement='right'] {
&[placement='end'] {
&::part(tablist) {
margin-right: 0.5rem;
margin-inline-start: 0.5rem;
}
> .tab-button {
&:hover {
translate: -2px 0;
[dir="rtl"] & {
translate: 2px 0;
}
}
}
}
@@ -362,13 +380,13 @@ tab-container {
> .tab-button {
&:first-of-type {
position: sticky;
left: 0;
inset-inline-start: 0;
@include z-index(base, 1);
}
&:last-of-type {
position: sticky;
right: 0;
inset-inline-end: 0;
@include z-index(base, 1);
}
}
@@ -417,44 +435,52 @@ tab-container {
}
// Left placement
&[placement='left'] {
&[placement='start'] {
&::part(tablist-tab-wrapper) {
border-right: 1px solid fi-var(global-border-color);
border-inline-end: 1px solid fi-var(global-border-color);
}
> .tab-button {
translate: 1px 0;
@include border-radius(left);
@include border-radius(start);
[dir="rtl"] & {
translate: -1px 0;
}
&[aria-selected='true'] {
border-right-color: fi-var(global-background-color);
border-inline-end-color: fi-var(global-background-color);
}
}
> .tab-panel {
border-left: none;
@include border-radius(right);
border-inline-start: none;
@include border-radius(end);
}
}
// Right placement
&[placement='right'] {
&[placement='end'] {
&::part(tablist-tab-wrapper) {
border-left: 1px solid fi-var(global-border-color);
border-inline-start: 1px solid fi-var(global-border-color);
}
> .tab-button {
translate: -1px 0;
@include border-radius(right);
@include border-radius(end);
[dir="rtl"] & {
translate: 1px 0;
}
&[aria-selected='true'] {
border-left-color: fi-var(global-background-color);
border-inline-start-color: fi-var(global-background-color);
}
}
> .tab-panel {
border-right: none;
@include border-radius(left);
border-inline-end: none;
@include border-radius(start);
}
}
}
@@ -608,14 +634,22 @@ tab-container .tab-panel:not([hidden]) {
border-top: 2px solid fi-var(tab-button-border-color);
}
&[placement='left'] > .tab-button {
&[placement='start'] > .tab-button {
translate: 2px 0;
border-right: 2px solid fi-var(tab-button-border-color);
border-inline-end: 2px solid fi-var(tab-button-border-color);
[dir="rtl"] & {
translate: -2px 0;
}
}
&[placement='right'] > .tab-button {
&[placement='end'] > .tab-button {
translate: -2px 0;
border-left: 2px solid fi-var(tab-button-border-color);
border-inline-start: 2px solid fi-var(tab-button-border-color);
[dir="rtl"] & {
translate: 2px 0;
}
}
}
@@ -81,7 +81,7 @@
position: absolute;
top: 1.25rem;
translate: 0 -50%;
left: 0;
inset-inline-start: 0;
text-align: center;
border-style: solid;
color: transparent;
@@ -99,7 +99,7 @@
content: '';
position: absolute;
top: 0;
left: calc(#{fi-var(timeline-circle-size)} / 2 + #{fi-var(timeline-width)} / 2);
inset-inline-start: calc(#{fi-var(timeline-circle-size)} / 2 + #{fi-var(timeline-width)} / 2);
width: fi-var(timeline-width);
height: 100%;
background-color: fi-var(timeline-color);
+1
View File
@@ -1,4 +1,5 @@
@use "common";
@use "reboot";
@use "root";
@use "rtl";
@use "layouts";
+2 -16
View File
@@ -219,7 +219,7 @@ fieldset {
// 2. Fix wrapping bug.
legend {
float: left; // 1
float: inline-start; // 1
width: 100%;
padding: 0;
margin-bottom: 0.5rem;
@@ -228,7 +228,7 @@ legend {
font-size: 1.5rem;
+ * {
clear: left; // 2
clear: inline-start; // 2
}
}
@@ -276,20 +276,6 @@ textarea {
}
}
// 1. A few input types should stay LTR
// See https://rtlstyling.com/posts/rtl-styling#form-inputs
// 2. RTL only output
// See https://rtlcss.com/learn/usage-guide/control-directives/#raw
/* rtl:raw:
[type="tel"],
[type="url"],
[type="email"],
[type="number"] {
direction: ltr;
}
*/
// Remove the inner padding in Chrome and Safari on macOS.
::-webkit-search-decoration {
+50
View File
@@ -0,0 +1,50 @@
// ==================================================================================
// Right-to-Left (RTL) Support
//
// See https://rtlstyling.com/posts/rtl-styling/
// See https://developer.apple.com/design/human-interface-guidelines/right-to-left/
// ==================================================================================
[dir="rtl"] {
// A few input types should stay LTR
[type="tel"],
[type="url"],
[type="email"],
[type="number"] {
direction: ltr;
}
// Flip directional icons in RTL
.fa-tags,
.fa-tag,
.fa-folder,
.fa-folder-tree,
.fa-folder-open,
.fa-folder-closed,
.fa-pencil,
.fa-pen-to-square,
.fa-pen-clip,
.fa-square-pen,
.fa-list-ul,
.fa-list-check,
.fa-clipboard-list,
.fa-rectangle-list,
.fa-comments,
.fa-comment,
.fa-comment-dots,
.fa-message,
.fa-retweet,
.octicon-report-16 {
scale: -1 1;
}
}
// Arabic-script languages (Arabic, Persian, Urdu) typography corrections
// Hebrew and other non-connected RTL scripts don't need these adjustments
// Letter-spacing breaks connected letter forms
:lang(ar),
:lang(fa),
:lang(ur) {
letter-spacing: 0;
}
+2 -2
View File
@@ -1,2 +1,2 @@
@forward "rgba" as fi-*;
@forward "var" as fi-*;
@forward "rgba";
@forward "var";
+2 -2
View File
@@ -5,6 +5,6 @@
/// @param {Number} $alpha [1] - Alpha channel value in range 0..1.
/// @example
/// color: fi-rgba(fi-var(secondary), 0.2);
@function rgba($color, $alpha: 1) {
@return string.unquote("rgb(from #{$color} r g b / #{$alpha})");
@function fi-rgba($color, $alpha: 1) {
@return rgb(from $color r g b / $alpha);
}
+3 -6
View File
@@ -9,13 +9,10 @@
/// @example
/// color: fi-var(global-font-color);
/// background: fi-var(custom-bg, #fff);
@function var($name, $fallback: null) {
@function fi-var($name, $fallback: null) {
@if $fallback != null {
@if meta.type-of($fallback) == string {
@return string.unquote('var(#{$rootPrefix}#{$name}, "#{$fallback}")');
}
@return string.unquote("var(#{$rootPrefix}#{$name}, #{$fallback})");
@return var(#{$rootPrefix}#{$name}, $fallback);
}
@return string.unquote("var(#{$rootPrefix}#{$name})");
@return var(#{$rootPrefix}#{$name});
}
+1 -2
View File
@@ -17,8 +17,7 @@ footer {
.footer-divider:not(:first-child)::before {
content: '|';
margin-left: 0.25rem;
margin-right: 0.25rem;
margin-inline: 0.25rem;
}
.hugo-icon,
+20 -8
View File
@@ -119,7 +119,7 @@ header {
list-style: none;
.dropdown-icon {
margin-left: 0.25rem;
margin-inline-start: 0.25rem;
font-size: .875em;
color: fi-var(global-font-color);
@@ -155,6 +155,10 @@ header {
position: relative;
@include focus-visible-ring;
[dir="rtl"] & {
scale: -1 1;
}
i {
display: inline-block;
rotate: 225deg;
@@ -195,10 +199,10 @@ header {
padding: 0 2rem;
height: 100%;
&[data-github-corner='left'] {
&[data-github-corner='start'] {
padding-inline-start: fi-var(header-height);
}
&[data-github-corner='right'] {
&[data-github-corner='end'] {
padding-inline-end: fi-var(header-height);
}
@@ -211,9 +215,17 @@ header {
&:hover .sub-menu {
display: block;
translate: -0.5rem 0;
[dir="rtl"] & {
translate: 0.5rem 0;
}
}
&.language-switch:hover .sub-menu {
translate: calc(1.75rem - 100%) 0;
[dir="rtl"] & {
translate: calc(100% - 1.75rem) 0;
}
}
}
@@ -229,7 +241,7 @@ header {
width: 0;
margin: 18.5px 0.5rem;
padding: 0;
border-left: 1.5px solid fi-var(global-border-color);
border-inline-start: 1.5px solid fi-var(global-border-color);
}
}
@@ -406,7 +418,7 @@ header {
padding: 0 1rem;
&:not(.menu-system):hover {
background-color: light-dark(#f2f2f3, #535355);
background-color: light-dark(#f2f2f3, #3e444c);
}
.menu-link {
@@ -448,7 +460,7 @@ header {
.language-select {
position: absolute;
opacity: 0;
left: 0;
inset-inline-start: 0;
top: 0;
width: 100%;
height: 100%;
@@ -457,7 +469,7 @@ header {
}
.sub-menu {
padding-left: 0;
padding-inline-start: 0;
display: none;
&.open {
@@ -465,7 +477,7 @@ header {
}
.menu-item:hover {
background-color: light-dark(#e7e7ea, #5d5d5f);
background-color: light-dark(#e7e7ea, #464c54);
}
}
+2 -1
View File
@@ -1,4 +1,5 @@
// Color map of admonitions
/// Color map of admonitions.
/// @type Map
$admonition-color-map: (
note: (
color: #448aff,
+4 -1
View File
@@ -1,4 +1,5 @@
// Color map of basic alerts
/// Color map of GitHub-style alerts (light theme).
/// @type Map
$alert-color-map: (
note: (
border-color: #0969da,
@@ -22,6 +23,8 @@ $alert-color-map: (
),
) !default;
/// Color map of GitHub-style alerts (dark theme).
/// @type Map
$alert-color-map-dark: (
note: (
border-color: #316dca,
+1 -1
View File
@@ -1,6 +1,6 @@
/// Map of code identifiers/languages to Chroma supported languages.
/// This file is auto-generated by `pnpm gen:lexers`, do not edit manually.
/// @see https://github.com/hugo-fixit/FixIt/tree/main/packages/chroma-lexers
/// See: https://github.com/hugo-fixit/FixIt/tree/main/packages/chroma-lexers
$chroma-lexers: (
"🔥": "Mojo",
"1s": "OnesEnterprise",
+2 -1
View File
@@ -1,4 +1,5 @@
// Theme colors map
/// Theme semantic color tokens.
/// @type Map
$theme-colors: (
'primary': #1677ff,
'secondary': #8b949e,
+8 -5
View File
@@ -1,12 +1,13 @@
@use "core/functions" as *;
/// Mixin to set border-radius
/// @param {String|Number|List} $value - The value of the border-radius, position (top, bottom, left, right) or keyword (full)
/// @param {String|Number|List} $value - The value of the border-radius, position (top, bottom, start, end) or keyword (full)
/// @param {Number} $radius - The radius of the border (only for position)
/// @example
/// @include border-radius;
/// @include border-radius(full);
/// @include border-radius(top);
/// @include border-radius(start);
/// @include border-radius(top, 10px);
/// @include border-radius(10px 20px 10px 20px);
@mixin border-radius($value: fi-var(global-border-radius), $radius: fi-var(global-border-radius)) {
@@ -16,10 +17,12 @@
border-radius: $radius $radius 0 0;
} @else if $value == bottom {
border-radius: 0 0 $radius $radius;
} @else if $value == left {
border-radius: $radius 0 0 $radius;
} @else if $value == right {
border-radius: 0 $radius $radius 0;
} @else if $value == start {
border-start-start-radius: $radius;
border-end-start-radius: $radius;
} @else if $value == end {
border-start-end-radius: $radius;
border-end-end-radius: $radius;
} @else {
border-radius: $value;
}
+6 -1
View File
@@ -1,6 +1,8 @@
@use "core/functions" as *;
// TODO Superseded by text-wrap: wrap; in modern browsers
/// Apply word-wrap and overflow-wrap for cross-browser compatibility.
/// TODO Superseded by `text-wrap: wrap;` in modern browsers.
/// @param {String} $value - Wrap value (e.g. `break-word`)
@mixin overflow-wrap($value) {
word-wrap: $value;
overflow-wrap: $value;
@@ -43,6 +45,9 @@
}
}
/// Apply a focus-visible ring outline using a pseudo-element.
/// @param {Length} $size [$size: 1.3em] - Size of the focus ring
/// @param {Length} $offset [$offset: 0.2rem] - Offset from the element
@mixin focus-visible-ring($size: 1.3em, $offset: 0.2rem) {
&:focus-visible {
outline: none;
@@ -2,6 +2,7 @@
@use "border-radius" as *;
@use "compatibility" as *;
/// Shared inline code styles using theme CSS variables.
@mixin inline-code() {
padding: 0.2em 0.4em;
margin: 0;
+1 -1
View File
@@ -1,7 +1,7 @@
@use "core/functions" as *;
@use "z-index" as *;
// Loading Mixin for before/after pseudo element
/// Loading pseudo-element styles for async content.
@mixin loading {
content: '';
position: absolute;
+2
View File
@@ -11,6 +11,8 @@
@use "sass:map";
@use "sass:list";
/// Responsive breakpoints map for the `media` mixin.
/// @type Map
$breakpoints: (
'xs': null,
'sm': 680px,
@@ -1,5 +1,8 @@
@use "theme-vars" as *;
/// Set scrollbar width CSS custom properties.
/// @param {String} $width [$width: thin] - Scrollbar width value
/// @param {Length} $widthLegacy [$widthLegacy: 12px] - Legacy scrollbar width
@mixin scrollbar-width($width: thin, $widthLegacy: 12px) {
@include set-fi-vars((
scrollbar-width: $width,
+5 -2
View File
@@ -1,8 +1,11 @@
@use "variables" as *;
// Shared defaults for theme-switch icon motion.
// Keep them overridable so other entries can reuse the same mixin with different pacing.
/// Duration of the theme-switch icon animation.
/// @type Time
$theme-switch-animation-duration: 0.5s !default;
/// Easing function for the theme-switch icon animation.
/// @type String
$theme-switch-animation-easing: cubic-bezier(0.22, 1, 0.36, 1) !default;
/// Bind a theme mode selector to an icon glyph and its matching animation.
+2
View File
@@ -1,5 +1,7 @@
@use "sass:map";
/// Z-index scale for consistent layering across the theme.
/// @type Map
$z-indexes: (
"hide": -1,
"auto": auto,
+2 -2
View File
@@ -8,7 +8,7 @@
font-size: 1.6rem;
font-weight: bold;
line-height: 140%;
text-align: right;
text-align: end;
}
.single-subtitle {
@@ -16,7 +16,7 @@
font-size: 1.2rem;
font-weight: normal;
line-height: 100%;
text-align: right;
text-align: end;
}
.group-title {
+6 -5
View File
@@ -12,7 +12,7 @@
.card-item {
font-size: 0.875rem;
text-align: left;
text-align: start;
width: 45%;
display: flex;
align-items: flex-start;
@@ -37,8 +37,8 @@
}
.more-post {
text-align: right;
padding-right: 1rem;
text-align: end;
padding-inline-end: 1rem;
}
}
@@ -53,7 +53,8 @@
justify-content: space-between;
align-items: center;
box-sizing: border-box;
margin: 0.25rem 0 0.25rem 1.5rem;
margin-block: 0.25rem;
margin-inline: 1.5rem 0;
}
.archive-item-link {
@@ -65,7 +66,7 @@
}
.archive-item-date {
text-align: right;
text-align: end;
color: fi-var(global-font-secondary-color);
white-space: nowrap;
font-variant-numeric: tabular-nums lining-nums;
+2 -2
View File
@@ -111,7 +111,7 @@
position: absolute;
width: 100%;
height: 100%;
left: 0;
inset-inline-start: 0;
top: 0;
object-fit: cover;
}
@@ -152,7 +152,7 @@
.post-tag:not(:last-child)::after {
content: ',';
margin-right: 0.25rem;
margin-inline-end: 0.25rem;
}
}
}
+14 -6
View File
@@ -16,7 +16,7 @@
&:has(.collection-nav-item:nth-child(2))::before {
content: '';
position: absolute;
left: 50%;
inset-inline-start: 50%;
bottom: 0.75rem;
width: 1px;
height: 2rem;
@@ -55,6 +55,10 @@
i {
flex-shrink: 0;
[dir="rtl"] & {
scale: -1 1;
}
}
span {
@@ -65,7 +69,7 @@
}
&[rel='next'] {
text-align: right;
text-align: end;
}
&[rel='prev']:hover {
@@ -104,7 +108,7 @@
&.open {
.collection-summary {
background-color: light-dark(color.adjust($global-background-color, $lightness: -5%), color.adjust($global-background-color-dark, $lightness: 5%));
background-color: light-dark(color.adjust($global-background-color, $lightness: -4%), color.adjust($global-background-color-dark, $lightness: 4%));
}
}
@@ -114,7 +118,8 @@
gap: 0.25em;
padding: 0.2em 0.5em;
user-select: none;
background-color: light-dark(color.adjust($global-background-color, $lightness: -5%), color.adjust($global-background-color-dark, $lightness: 5%));
background-color: light-dark(color.adjust($global-background-color, $lightness: -4.5%), color.adjust($global-background-color-dark, $lightness: 4.5%));
transition: background-color 0.2s ease;
> i.fa-layer-group {
flex-shrink: 0;
@@ -158,7 +163,7 @@
.collection-item > span::before {
content: '|';
font-weight: 600;
margin-right: 0.5em;
margin-inline-end: 0.5em;
position: relative;
bottom: 2px;
color: fi-var(single-link-color);
@@ -179,7 +184,10 @@
align-items: center;
justify-content: center;
gap: 0.5em;
background-color: light-dark(color.adjust($global-background-color, $lightness: -5%), color.adjust($global-background-color-dark, $lightness: 5%));
[dir="rtl"] & i {
scale: -1 1;
}
a.collection-nav-item {
padding-inline: 2px;
+63
View File
@@ -0,0 +1,63 @@
@use "core/functions" as *;
@use "core/mixins" as *;
@keyframes disclaimer-shimmer {
0% {
background-position: 100% 0;
}
100% {
background-position: -100% 0;
}
}
@keyframes disclaimer-shimmer-rtl {
0% {
background-position: -100% 0;
}
100% {
background-position: 100% 0;
}
}
.post-disclaimer {
display: flex;
align-items: center;
gap: 0.25em;
padding: 0.25rem 0;
font-size: 0.8em;
color: fi-var(global-font-tertiary-color);
.post-disclaimer__content {
background: linear-gradient(
90deg,
fi-var(global-font-tertiary-color) 0%,
fi-var(global-font-tertiary-color) 40%,
fi-var(global-font-color) 50%,
fi-var(global-font-tertiary-color) 60%,
fi-var(global-font-tertiary-color) 100%
);
background-size: 200% 100%;
background-clip: text;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
animation: disclaimer-shimmer 3s linear infinite;
@include media('reduce-motion') {
animation: none;
}
[dir="rtl"] & {
animation-name: disclaimer-shimmer-rtl;
}
}
.icon {
flex-shrink: 0;
padding-inline: 0.125em;
color: fi-var(global-font-secondary-color);
}
svg.icon {
width: 1.25em;
height: 1.25em;
}
}
+8 -10
View File
@@ -18,7 +18,7 @@
.post-info-mod {
font-size: 0.8em;
color: fi-var(global-font-secondary-color);
color: fi-var(global-font-secondary-color);
@include link(false, false);
}
@@ -38,8 +38,7 @@
>span:not(:first-child)::before {
content: '|';
margin-left: 0.25rem;
margin-right: 0.25rem;
margin-inline: 0.25rem;
color: fi-var(global-font-secondary-color);
}
}
@@ -71,16 +70,11 @@
.post-tags {
max-width: 65%;
* {
display: inline;
}
@include link(true, true);
.post-tag:not(:last-child)::after {
content: ',';
margin-right: 0.25rem;
margin-inline-end: 0.25rem;
}
}
@@ -96,8 +90,12 @@
font-weight: 600;
transition: all 0.3s ease-out;
[dir="rtl"] & i {
scale: -1 1;
}
&[rel='next'] {
text-align: right;
text-align: end;
}
&[rel='prev']:hover {
+1
View File
@@ -1,4 +1,5 @@
@use "collections";
@use "disclaimer";
@use "footer";
@use "related";
@use "toc";
+1 -1
View File
@@ -59,7 +59,7 @@
.related-item > span::before {
content: '|';
font-weight: 600;
margin-right: 0.5em;
margin-inline-end: 0.5em;
position: relative;
bottom: 2px;
color: fi-var(single-link-color);
+82 -21
View File
@@ -21,29 +21,46 @@
ul {
margin: 0;
text-indent: -0.8em;
padding-left: 0.8em;
padding-inline-start: 0.8em;
list-style: none;
a:first-child::before {
content: '|';
font-weight: bolder;
margin-right: 0.5em;
margin-inline-end: 0.5em;
position: relative;
bottom: 2px;
color: fi-var(single-link-color);
}
ul {
padding-left: 1em;
padding-inline-start: 1em;
}
}
ol {
margin: 0;
padding-left: 2.25em;
padding-inline-start: 3ch;
list-style: none;
counter-reset: toc-counter;
ol {
padding-left: 1.25em;
// 10+ items → 2-digit marker
&:has(> :nth-child(10)) {
padding-inline-start: 4ch;
}
// 100+ items → 3-digit marker
&:has(> :nth-child(100)) {
padding-inline-start: 5ch;
}
> li {
counter-increment: toc-counter;
&::marker {
content: counters(toc-counter, ".") ". ";
color: fi-var(global-font-secondary-color);
}
}
li:has(> a:hover)::marker {
@@ -63,7 +80,7 @@
// Common active state styles for auto and dialog TOC
#toc-auto,
#toc-dialog {
#nav-dialog {
.toc-content {
li.has-active {
&::marker {
@@ -100,6 +117,8 @@
@include sticky-top-offset;
.toc-title {
display: flex;
align-items: center;
margin-block: 0 0.5em;
cursor: pointer;
user-select: none;
@@ -107,7 +126,7 @@
&::before {
content: '|';
font-weight: bolder;
margin-right: 0.5em;
margin-inline-end: 0.5em;
position: relative;
bottom: 2px;
color: fi-var(global-border-color);
@@ -116,16 +135,36 @@
i.toc-icon {
transition: rotate 0.2s ease;
}
.toc-print-btn {
padding: 0;
border: none;
background: none;
color: fi-var(global-font-secondary-color);
cursor: pointer;
margin-inline-start: auto;
transition: color 0.2s ease;
&:hover {
color: fi-var(global-font-color);
}
}
}
&.toc-hidden i.toc-icon {
rotate: -90deg;
transition: rotate 0.2s ease;
[dir="rtl"] & {
rotate: 90deg;
}
}
.toc-content {
overflow-y: auto;
max-height: fi-var(toc-content-max-height, 90dvh);
mask-image: linear-gradient(to bottom, transparent 0%, black 2%, black 98%, transparent 100%);
-webkit-mask-image: linear-gradient(to bottom, transparent 0%, black 2%, black 98%, transparent 100%);
@include scrollbar-width(none, 0);
&.always-active ul,
@@ -194,7 +233,8 @@
}
> ol {
padding: 0.4em 1em 0.4em 2.25em;
padding-block: 0.4em;
padding-inline-end: 1em;
li:has(> a:hover)::marker,
a:hover {
@@ -218,16 +258,16 @@
}
}
#toc-dialog {
#nav-dialog {
opacity: 0;
translate: 100vw 0;
width: MIN(calc(100% - 4rem), 460px);
height: 100dvh;
max-width: 100%;
max-height: 100%;
margin-right: 0;
margin-inline-end: 0;
border: none;
border-left: 1px solid fi-var(global-border-color-light);
border-inline-start: 1px solid fi-var(global-border-color-light);
background-color: fi-var(global-background-color);
transition:
display 0.2s allow-discrete,
@@ -235,10 +275,14 @@
translate 0.2s,
opacity 0.2s 0.4s;
.toc-close-btn {
[dir="rtl"] & {
translate: -100vw 0;
}
.nav-close-btn {
position: absolute;
top: 1.25rem;
right: 1rem;
inset-inline-end: 1rem;
padding: 0.25rem;
color: fi-var(global-font-secondary-color);
transition: color 0.2s ease;
@@ -255,19 +299,32 @@
margin-inline: 1rem;
.toc-title {
font-size: calc(#{fi-var(toc-title-font-size)} * 1.5);
line-height: calc(#{fi-var(toc-title-font-size)} * 2);
margin-block: fi-var(toc-title-font-size);
font-size: 1.25rem;
line-height: 2rem;
margin-block: 1rem 0.75rem;
}
.toc-content {
font-size: MAX(fi-var(toc-content-font-size), 1rem);
// toc and collection tabs in dialog
> tab-container {
flex-direction: column;
margin-block: 0;
nav {
max-height: calc(100dvh - 5rem);
> .tab-button {
padding: 0.5rem;
}
> .tab-panel {
max-height: calc(100dvh - 8rem);
overflow: auto;
}
}
// only toc-content or collection-content in dialog
> .toc-content,
> .collection-content {
max-height: calc(100dvh - 5rem);
overflow: auto;
}
}
&::backdrop {
@@ -302,6 +359,10 @@
&[open] {
translate: 100vw 0;
[dir="rtl"] & {
translate: -100vw 0;
}
}
}
}
+8
View File
@@ -14,6 +14,10 @@
color: fi-var(global-font-secondary-color);
transition: all 0.2s ease;
[dir="rtl"] & {
scale: -1 1;
}
&:hover {
color: fi-var(global-font-color);
}
@@ -33,6 +37,10 @@
i.details-icon {
rotate: 90deg;
[dir="rtl"] & {
rotate: -90deg;
}
}
}
+2 -2
View File
@@ -3,7 +3,7 @@
.fixed-buttons {
position: fixed;
right: 1.5rem;
inset-inline-end: 1.5rem;
bottom: 1.5rem;
display: flex;
flex-direction: column;
@@ -49,7 +49,7 @@
svg {
position: absolute;
top: 0;
left: 0;
inset-inline-start: 0;
width: 100%;
height: 100%;
// Rotate to start from top
+1 -1
View File
@@ -5,7 +5,7 @@
background-position: center;
position: fixed;
top: 0;
left: 0;
inset-inline-start: 0;
width: 100%;
height: 100%;
@include z-index(hide);
+7 -7
View File
@@ -12,8 +12,7 @@ dialog.search-dialog {
// Anchor to top and center horizontally with fixed dimensions
// to prevent position jumps when results appear/disappear.
top: 15vh;
left: 50%;
margin: 0;
margin: 0 auto;
&::backdrop {
background-color: rgba(0, 0, 0, 0.25);
@@ -219,7 +218,7 @@ dialog.search-dialog {
.suggestion-heading-mark {
color: fi-var(global-font-tertiary-color);
margin-right: 0.125rem;
margin-inline-end: 0.125rem;
}
em {
@@ -255,7 +254,7 @@ dialog.search-dialog {
color: fi-var(global-font-tertiary-color);
i {
margin-right: 0.125rem;
margin-inline-end: 0.125rem;
}
}
@@ -346,6 +345,7 @@ dialog.search-dialog {
&:modal {
inset: 0;
width: 100%;
height: 100dvh;
max-width: 100%;
max-height: 100dvh;
translate: 0 0;
@@ -369,7 +369,7 @@ dialog.search-dialog {
@include media('sm', 'up') {
opacity: 0;
translate: -50% 12px;
translate: 0 12px;
scale: 0.98;
transition:
display 0.2s allow-discrete,
@@ -380,7 +380,7 @@ dialog.search-dialog {
&[open] {
opacity: 1;
translate: -50% 0;
translate: 0 0;
scale: 1;
}
@@ -403,7 +403,7 @@ dialog.search-dialog {
}
&[open] {
translate: -50% 12px;
translate: 0 12px;
scale: 0.98;
}
}
+9 -8
View File
@@ -33,16 +33,17 @@
fill: fi-var(github-corner-fill);
}
&.left {
left: 0;
svg {
scale: -1 1;
}
&.start {
inset-inline-start: 0;
}
&.right {
right: 0;
&.end {
inset-inline-end: 0;
}
// Flip octocat to face the start side
:is([dir="ltr"] &.start, [dir="rtl"] &.end) svg {
scale: -1 1;
}
@include media('print') {
+53 -29
View File
@@ -90,7 +90,7 @@ pre = ""
# You can add extra information after the name (HTML format is supported), such as icons.
post = ""
name = "Archives"
url = "/archives/"
url = "archives/"
# Title will be shown when you hover on this menu link.
title = ""
weight = 1
@@ -99,7 +99,8 @@ weight = 1
[menus.main.params]
# Add CSS class to a specific menu item.
class = ""
# Whether set as a draft menu item whose function is similar to a draft post/page.
# Whether set as a draft menu item, hidden by default.
# Visible when env var is set: HUGO_PARAMS_MENU_DRAFT=true hugo server
draft = false
# Add FontAwesome icon to a specific menu item.
icon = "fa-solid fa-archive"
@@ -115,7 +116,7 @@ parent = ""
pre = ""
post = ""
name = "Categories"
url = "/categories/"
url = "categories/"
title = ""
weight = 2
@@ -128,7 +129,7 @@ parent = ""
pre = ""
post = ""
name = "Tags"
url = "/tags/"
url = "tags/"
title = ""
weight = 3
@@ -401,6 +402,15 @@ rel = "manifest"
isPlainText = true
isHTML = false
# Options to make output llms.txt file (AI-friendly site map).
# Add "llms" to home outputs to enable.
[outputFormats.llms]
baseName = "llms"
mediaType = "text/plain"
isPlainText = true
isHTML = false
notAlternative = true
# -------------------------------------------------------------------------------------
# Output Configuration
# See: https://gohugo.io/configuration/outputs/
@@ -676,7 +686,7 @@ wrapper = true
cdn = "https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.esm.min.mjs"
# ZenUML ESM module CDN source.
# You can set it to a CDN source to enable ZenUML support.
# Example: `https://cdn.jsdelivr.net/npm/@mermaid-js/mermaid-zenuml/dist/mermaid-zenuml.esm.min.mjs`.
# Example: `https://cdn.jsdelivr.net/npm/@mermaid-js/mermaid-zenuml/dist/mermaid-zenuml.esm.min.mjs`
zenuml = ""
# For values, See: [Available Themes](https://mermaid.js.org/config/theming.html#available-themes).
themes = [
@@ -692,7 +702,7 @@ look = "handDrawn"
# Specifies the font to be used in the rendered diagrams.
font_family = ""
# Layout loaders from ESM module CDN sources (e.g., ELK layout engine).
# Example: ["https://cdn.jsdelivr.net/npm/@mermaid-js/layout-elk/dist/mermaid-layout-elk.esm.min.mjs"].
# Example: ["https://cdn.jsdelivr.net/npm/@mermaid-js/layout-elk/dist/mermaid-layout-elk.esm.min.mjs"]
# This will enable additional layout options: ["elk", "elk.layered", "elk.stress", "elk.force", "elk.mrtree"].
layout_loaders = []
# Default layout algorithm for rendering diagrams.
@@ -709,8 +719,8 @@ keep_static = false
# Whether to make the table of the contents in the sidebar automatically collapsed.
auto = true
# Position of TOC.
# available values: ["left", "right"]
position = "right"
# available values: ["start", "end"]
position = "end"
# Supersede `markup.tableOfContents` settings.
ordered = false
start_level = 2
@@ -718,6 +728,16 @@ end_level = 6
# Whether to decrease the H1 heading level in content.
decrease_h1 = false
# Post disclaimer/declaration.
[params.disclaimer]
# Whether to enable the disclaimer.
enable = false
# Disclaimer type.
# available values: ["ai", "repost", "original", "custom"]
type = "ai"
# Custom disclaimer content (optional, uses i18n default if empty).
content = ""
# Display a message at the beginning of an article to warn the reader that its content might be expired.
[params.expiration_reminder]
enable = false
@@ -740,14 +760,6 @@ enable = false
# Only enable in main section pages (default is posts).
only_main_section = true
[params.heading.number.format]
h1 = "{title}"
h2 = "{h2} {title}"
h3 = "{h2}.{h3} {title}"
h4 = "{h2}.{h3}.{h4} {title}"
h5 = "{h2}.{h3}.{h4}.{h5} {title}"
h6 = "{h2}.{h3}.{h4}.{h5}.{h6} {title}"
# Mathematical formulas configuration.
# See: [Formula](https://fixit.lruihao.cn/docs/content-management/markdown-syntax/extended/#formula)
[params.math]
@@ -859,9 +871,9 @@ user_desc = ""
# DOM container to be blacked out, e.g. [".aplayer"]
black_dom = []
# only for iframe mode
# Example: "375px".
# Example: "375px"
frame_width = ""
# Example: "600px".
# Example: "600px"
frame_height = ""
# Only for magic mode.
user_icon = ""
@@ -1157,27 +1169,39 @@ light_theme = "light"
dark_theme = "dark"
lazy_load = true
# robots.txt configuration (requires enableRobotsTXT = true).
[params.robots]
# Allow AI crawlers (unblock GPTBot/ClaudeBot etc.) + Content-Signal comment + AI hidden hint.
allow_crawlers = false
# Custom rules appended to robots.txt (optional).
# [[params.robots.rules]]
# user_agent = "SomeBot"
# disallow = "/"
# [[params.robots.rules]]
# user_agent = "GoodBot"
# allow = "/"
# Third-party library configuration for some custom CSS and JS files.
# Files can be loaded from local assets (relative to /assets/) or remote CDN URLs.
# The key is a unique identifier, the value is the file path or URL.
[params.library]
# Load some CSS from local assets.
# Example: someCSS = "css/some.css".
# Example: `someCSS = "css/some.css"`
# Load some CSS from remote CDN.
# Example: someCSS = "https://cdn.example.com/some.css".
# Example: `someCSS = "https://cdn.example.com/some.css"`
[params.library.css]
# Load some JS from local assets.
# Example: someJS = "js/some.js".
# Example: `someJS = "js/some.js"`
# Load some JS from remote CDN.
# Example: someJS = "https://cdn.example.com/some.js".
# Example: `someJS = "https://cdn.example.com/some.js"`
[params.library.js]
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# Public Git repository information only then enableGitInfo is true.
[params.git_info]
# Example: "https://github.com/hugo-fixit/docs".
# Example: `"https://github.com/hugo-fixit/docs"`
repo = ""
branch = "main"
# The content directory path relative to the root of the repository.
@@ -1373,7 +1397,7 @@ enable = false
animate = true
icon = "fa-solid fa-heartbeat"
pre = ""
# Example: "2021-12-18T16:15:22+08:00".
# Example: "2021-12-18T16:15:22+08:00"
value = ""
# Footer lines order.
@@ -1744,13 +1768,13 @@ polyfill = false
# Whether to use object-fit-images to be compatible with older browsers.
object_fit = false
# GitHub banner in the top-right or top-left corner.
# GitHub banner in the header corner.
[params.github_corner]
enable = false
permalink = "https://github.com/hugo-fixit/FixIt"
title = "View source on GitHub"
# available values: ["left", "right"]
position = "right"
# available values: ["start", "end"]
position = "end"
# Gravatar configuration.
[params.gravatar]
@@ -1771,8 +1795,8 @@ scrollpercent = false
# Reading progress bar.
[params.reading_progress]
enable = false
# available values: ["left", "right"]
start = "left"
# available values: ["start", "end"]
start = "start"
# available values: ["top", "bottom"]
position = "top"
reversed = false
+272
View File
@@ -0,0 +1,272 @@
# Translations for Arabic
# الترجمة إلى العربية
# https://gohugo.io/content-management/multilingual/#translation-of-strings
# === Init ===
[init]
hugoVersionError = "إصدار Hugo منخفض جداً.\n\nالإصدار الحالي هو {{ .Current }}، والإصدار الأدنى المطلوب لـ FixIt هو {{ .Minimal }}.\n\nإذا كنت تستخدم Hugo على جهازك الشخصي، راجع https://gohugo.io/getting-started/installing/#upgrade-hugo لدليل الترقية.\n\nإذا كنت تستخدم Hugo على منصة طرف ثالث، يرجى تكوين إصدار Hugo وفقاً لذلك."
configurationError = "خطأ في التكوين\nلم تقم بتكوين معامل إصدار FixIt بشكل صحيح بعد. راجع https://fixit.lruihao.cn/docs/getting-started/configuration/params/"
compatibilityError = "خطأ في التوافق ({{ .From }} -> {{ .To }}):\nلديك تحديث غير متوافق. راجع https://github.com/hugo-fixit/FixIt/releases"
devVersionWarn = "أنت تستخدم إصدار تطوير من FixIt. يُرجى التفكير في استخدام إصدار مستقر.\nراجع https://github.com/hugo-fixit/FixIt/releases"
devEnvWarn = "البيئة الحالية هي \"development\". سيتم تعطيل \"نظام التعليقات\"، \"PWA\"، \"CDN\"، \"البصمة الرقمية\" و\"التحليلات\"."
quicklyUpgrade = "للترقية السريعة استخدم الأمر: "
# === Init ===
# === Base Layout ===
[baseof]
backToTop = "العودة للأعلى"
viewComments = "عرض التعليقات"
noscript = "يعمل هذا الموقع بشكل أفضل مع تمكين JavaScript."
# === Base Layout ===
# === Taxonomy ===
[archives]
other = "الأرشيف"
[allSome]
other = "جميع {{ .Some }}"
[category]
other = "التصنيف"
[categories]
other = "التصنيفات"
[collection]
other = "المجموعة"
[collections]
other = "المجموعات"
[tag]
other = "الوسم"
[tags]
other = "الوسوم"
[posts]
other = "المقالات"
# === Taxonomy ===
# === Section ===
[section]
recentlyUpdated = "تم التحديث مؤخراً"
[section.totalWordCount]
one = "كلمة واحدة"
other = "{{ .Count }} كلمة"
[section.archiveCounter]
one = "مقال واحد فقط"
other = "{{ .Count }} مقالة"
# === Section ===
# === Pagination ===
[pagination]
more = "المزيد"
# === Pagination ===
# === Header ===
[header]
selectLanguage = "اختر اللغة"
noTranslations = "لا توجد ترجمات"
switchTheme = "تغيير السمة"
# === Header ===
# === Footer ===
[footer]
poweredBySome = "بدعم من {{ .Hugo }} | السمة - {{ .Theme }}"
siteUV = "إجمالي الزوار"
sitePV = "إجمالي الزيارات"
siteRunning = "الموقع يعمل منذ ..."
# === Footer ===
# === Comment ===
[comment]
valinePlaceholder = "تعليقك ..."
# === Comment ===
# === Assets ===
[assets]
search = "بحث"
searchPlaceholder = "ابحث في العناوين أو المحتوى ..."
searchIn = "ابحث في {{ . }}"
searchBy = "بحث بواسطة"
gotoResultsPage = "الذهاب إلى صفحة نتائج البحث ..."
clear = "مسح"
cancel = "إلغاء"
navigate = "تنقل"
select = "تحديد"
close = "إغلاق"
refresh = "تحديث"
noResultsFound = "لم يتم العثور على نتائج"
copyToClipboard = "نسخ إلى الحافظة"
copyText = "نسخ"
copiedText = "تم النسخ"
toggleLineNumbers = "إظهار/إخفاء أرقام الأسطر"
toggleLineWrap = "إظهار/إخفاء التفاف الأسطر"
toggleCodeEditable = "إظهار/إخفاء تحرير كتلة الكود"
downloadCode = "تحميل الكود"
expandCode = "توسيع أو طي كتلة الكود"
fullscreen = "ملء الشاشة"
exitFullscreen = "الخروج من ملء الشاشة"
cookieconsentMessage = "يستخدم هذا الموقع ملفات تعريف الارتباط لتحسين تجربتك."
cookieconsentDismiss = "فهمت!"
cookieconsentLink = "اعرف المزيد"
# === Assets ===
# === Share ===
[shareOn]
other = "مشاركة على"
# === Share ===
# === Single Post ===
[single]
contents = "المحتويات"
navigation = "التنقل"
disclaimer = "تنبيه: "
pin = "تثبيت في الأعلى"
repost = "إعادة النشر"
publishedOnDate = "نُشر في {{ .Date }}"
views = "مشاهدات"
comments = "تعليقات"
author = "المؤلف"
updatedOnDate = "تم التحديث في {{ .Date }}"
readMarkdown = "قراءة Markdown"
viewSource = "عرض المصدر"
editThisPage = "تعديل هذه الصفحة"
reportIssue = "الإبلاغ عن مشكلة"
openInEditor = "فتح في المحرر"
back = "رجوع"
home = "الرئيسية"
readMore = "اقرأ المزيد"
expirationReminder = "تم تحديث هذا المقال آخر مرة في {{ .Date }}، وقد يكون المحتوى قديماً."
encryptedAbstract = "تم تشفير هذا المقال، لذا المحتوى الأصلي غير مرئي!"
print = "طباعة"
encryptedMessage = "يرجى إدخال كلمة المرور"
password = "كلمة المرور"
enterBtn = "دخول"
encryptyAgain = "تشفير مرة أخرى"
encryptionWarning = "تم اكتشاف تشفير المحتوى، لكنه لا يزال بنص عادي!"
[single.disclaimerMessage]
ai = "تم إنشاء هذا المقال بواسطة الذكاء الاصطناعي. يرجى التحقق من المعلومات بشكل مستقل."
repost = "هذا المقال هو إعادة نشر. يرجى زيارة المصدر الأصلي لمزيد من المعلومات."
original = "هذا هو المحتوى الأصلي للمؤلف."
encryptionCommand = "قم بتشغيل `npx @hugo-fixit/encrypt` بعد البناء لتشفيره فعلياً."
relatedContent = "محتوى ذي صلة"
[single.includedIn]
categories = "مدرجة في {{ .Categories }}"
collections = "مدرجة في {{ .Collections }}"
both = "مدرجة في {{ .Categories }} و {{ .Collections }}"
[single.wordCount]
one = "كلمة واحدة"
other = "{{ .Count }} كلمة"
[single.fuzzyWordCount]
other = "حوالي {{ .Count }} كلمة"
[single.readingTime]
one = "دقيقة واحدة"
other = "{{ .Count }} دقائق"
[single.reward]
donate = "تبرع"
wechatpay = "WeChat Pay"
alipay = "Alipay"
paypal = "PayPal"
bitcoin = "Bitcoin"
# === Single Post ===
# === Error Pages ===
[pageNotFound]
other = "الصفحة غير موجودة"
[pageNotFoundText]
other = "الصفحة التي تبحث عنها غير موجودة. نعتذر عن ذلك."
# === Error Pages ===
# === Offline ===
[offlineTitle]
other = "غير متصل"
[offlineText]
other = "أنت غير متصل بالإنترنت، ستكون فقط الصفحات المخزنة مؤقتاً متاحة."
# === Offline ===
# === Service Worker ===
[serviceWorker]
updateTitle = "تحديث متاح"
updateText = "يتوفر إصدار جديد من هذا الموقع."
# === Service Worker ===
# === Link Redirection ===
[linkRedirection]
title = "إشعار إعادة التوجيه"
message = "أنت على وشك مغادرة {{ .Title }}، يرجى الانتباه إلى أمان حسابك وممتلكاتك."
confirm = "متابعة الزيارة"
# === Link Redirection ===
# === Alert ===
[alert]
note = "ملاحظة"
tip = "نصيحة"
important = "مهم"
warning = "تحذير"
caution = "انتبه"
# === Alert ===
# === Task List ===
[taskList]
x = "تم التحقق"
" " = "لم يتم التحقق"
"/" = "قيد التنفيذ"
"-" = "ملغى"
"<" = "مجدول"
">" = "أُعيد جدولته"
"!" = "مهم"
"!x" = "مهم - تم التحقق"
"?" = "سؤال"
# === Task List ===
# === Admonition ===
[admonition]
note = "ملاحظة"
abstract = "ملخص"
info = "معلومات"
todo = "المهام"
tip = "نصيحة"
success = "نجاح"
question = "سؤال"
warning = "تحذير"
failure = "فشل"
danger = "خطر"
bug = "خلل"
example = "مثال"
quote = "اقتباس"
# === Admonition ===
# === Version ===
[version]
new = "جديد"
changed = "تم التغيير"
deleted = "تم الحذف"
deprecated = "متقادم"
# === Version ===
# === Diagram ===
[diagram]
zoomIn = "تكبير"
zoomOut = "تصغير"
reset = "إعادة تعيين"
download = "تحميل SVG"
# === Diagram ===
# === Tabs ===
[tabs]
diagram = "مخطط"
code = "الكود"
# === Tabs ===
+9 -2
View File
@@ -5,7 +5,6 @@
# === Init ===
[init]
hugoVersionError = "Hugo-Version ist zu niedrig.\n\nAktuelle Hugo-Version ist {{ .Current }}, die minimal unterstützte Version für FixIt ist {{ .Minimal }}.\n\nWenn Sie Hugo auf Ihrem eigenen Computer ausführen, schauen Sie sich https://gohugo.io/getting-started/installing/#upgrade-hugo für eine Upgrade-Anleitung an.\n\nWenn Sie auf einer Drittanbieterplattform bereitstellen, konfigurieren Sie bitte die Hugo-Version entsprechend."
hugoExtendedWarn = "Die Hugo Extended-Version ist für die Unterstützung von SCSS erforderlich."
configurationError = "Konfigurationsfehler\nSie haben den FixIt-Versionsparameter noch nicht korrekt konfiguriert. Siehe https://fixit.lruihao.cn/docs/getting-started/configuration/params/?lang=deutsch"
compatibilityError = "Kompatibilitätsfehler ({{ .From }} -> {{ .To }}):\nSie haben ein inkompatibles Update. Siehe https://github.com/hugo-fixit/FixIt/releases"
devVersionWarn = "Sie verwenden eine Entwicklungsversion von FixIt. Bitte erwägen Sie die Verwendung einer stabilen Version.\nSiehe https://github.com/hugo-fixit/FixIt/releases"
@@ -70,7 +69,7 @@ more = "Mehr"
# === Header ===
[header]
selectLanguage = "Sprache wählen"
noMoretTranslations = "Keine weiteren Übersetzungen"
noTranslations = "Keine Übersetzungen"
switchTheme = "Darstellung ändern"
# === Header ===
@@ -124,6 +123,8 @@ other = "Teilen auf"
# === Single Post ===
[single]
contents = "Inhalt"
navigation = "Navigation"
disclaimer = "Autorenhinweis: "
pin = "Oben anheften"
repost = "Erneut posten"
publishedOnDate = "veröffentlicht an {{ .Date }}"
@@ -141,12 +142,18 @@ home = "Startseite"
readMore = "Mehr lesen"
expirationReminder = "Dieser Artikel wurde zuletzt auf {{ .Date }} aktualisiert, der Inhalt kann veraltet sein."
encryptedAbstract = "Dieser Artikel wurde verschlüsselt, daher ist sein Rohinhalt unsichtbar!"
print = "Drucken"
encryptedMessage = "Bitte geben Sie das Passwort ein"
password = "Passwort"
enterBtn = "Eintreten"
encryptyAgain = "Erneut verschlüsseln"
encryptionWarning = "Inhaltsverschlüsselung erkannt, aber sie sind noch im Klartext!"
encryptionCommand = "Führen Sie `npx @hugo-fixit/encrypt` nach dem Build aus, um sie tatsächlich zu verschlüsseln."
[single.disclaimerMessage]
ai = "Dieser Artikel wurde von einer KI generiert. Bitte überprüfen Sie die Informationen unabhängig."
repost = "Dieser Artikel ist ein Repost. Bitte besuchen Sie die Originalquelle für weitere Informationen."
original = "Dies ist der Originalinhalt des Autors."
relatedContent = "Ähnliche Inhalte"
[single.includedIn]
+9 -2
View File
@@ -4,7 +4,6 @@
# === Init ===
[init]
hugoVersionError = "Hugo version is too low.\n\nCurrent Hugo version is {{ .Current }}, the minimum supported version for FixIt is {{ .Minimal }}.\n\nIf you are running Hugo on your own computer, check out https://gohugo.io/getting-started/installing/#upgrade-hugo for upgrading guide.\n\nIf you are deploying on a third-party platform, please configure Hugo version accordingly."
hugoExtendedWarn = "The Hugo Extended version is necessary for SCSS support."
configurationError = "Configuration Error\nYou haven't configured the FixIt version param correctly yet. See https://fixit.lruihao.cn/docs/getting-started/configuration/params/"
compatibilityError = "Compatibility Error ({{ .From }} -> {{ .To }}):\nYou have an incompatible update. See https://github.com/hugo-fixit/FixIt/releases"
devVersionWarn = "You are using a development version of FixIt. Please consider using a stable version.\nSee https://github.com/hugo-fixit/FixIt/releases"
@@ -70,7 +69,7 @@ more = "More"
# === Header ===
[header]
selectLanguage = "Select Language"
noMoretTranslations = "No more translations"
noTranslations = "No translations"
switchTheme = "Switch Theme"
# === Header ===
@@ -124,6 +123,8 @@ other = "Share on"
# === Single Post ===
[single]
contents = "Contents"
navigation = "Navigation"
disclaimer = "Disclaimer: "
pin = "Pin to top"
repost = "Repost"
publishedOnDate = "published on {{ .Date }}"
@@ -141,6 +142,7 @@ home = "Home"
readMore = "Read More"
expirationReminder = "This article was last updated on {{ .Date }}, the content may be out of date."
encryptedAbstract = "This article has been encrypted, so its raw content is invisible!"
print = "Print"
encryptedMessage = "Please enter the password"
password = "Password"
enterBtn = "Enter"
@@ -149,6 +151,11 @@ encryptionWarning = "Content encryption detected, but they are still in plaintex
encryptionCommand = "Run `npx @hugo-fixit/encrypt` after building to actually encrypt them."
relatedContent = "Related Content"
[single.disclaimerMessage]
ai = "This article was generated by AI. Please verify the information independently."
repost = "This article is a repost. Please visit the original source for more information."
original = "This is original content by the author."
[single.includedIn]
categories = "included in {{ .Categories }}"
collections = "included in {{ .Collections }}"
+9 -2
View File
@@ -5,7 +5,6 @@
# === Init ===
[init]
hugoVersionError = "Hugo versión es demasiado baja.\n\nLa versión actual de Hugo es {{ .Current }}, la versión mínima compatible para FixIt es {{ .Minimal }}.\n\nSi estás ejecutando Hugo en tu propia computadora, consulta https://gohugo.io/getting-started/installing/#upgrade-hugo para obtener una guía de actualización.\n\nSi estás desplegando en una plataforma de terceros, por favor configura la versión de Hugo en consecuencia."
hugoExtendedWarn = "La versión extendida de Hugo es necesaria para el soporte de SCSS."
configurationError = "Error de configuración\nAún no ha configurado correctamente el parámetro de versión de FixIt. Consulte https://fixit.lruihao.cn/docs/getting-started/configuration/params/?lang=spanish"
compatibilityError = "Error de compatibilidad ({{ .From }} -> {{ .To }}):\nTiene una actualización incompatible. Consulte https://github.com/hugo-fixit/FixIt/releases"
devVersionWarn = "Está utilizando una versión de desarrollo de FixIt. Considere usar una versión estable.\nConsulte https://github.com/hugo-fixit/FixIt/releases"
@@ -70,7 +69,7 @@ more = "Más"
# === Header ===
[header]
selectLanguage = "Selecciona el lenguage"
noMoretTranslations = "No hay más traducciones"
noTranslations = "Sin traducciones"
switchTheme = "Cambia el tema"
# === Header ===
@@ -124,6 +123,8 @@ other = "Compartir en"
# === Single Post ===
[single]
contents = "Contenido"
navigation = "Navegación"
disclaimer = "Aviso: "
pin = "Fijar en la parte superior"
repost = "Repostear"
publishedOnDate = "publicado el {{ .Date }}"
@@ -141,12 +142,18 @@ home = "Inicio"
readMore = "Leer más"
expirationReminder = "Este artículo se actualizó por última vez el {{ .Date }}, es posible que el contenido no esté actualizado."
encryptedAbstract = "Este artículo ha sido encriptado, por lo que su contenido bruto es invisible!"
print = "Imprimir"
encryptedMessage = "Por favor, ingrese la contraseña"
password = "Contraseña"
enterBtn = "Entrar"
encryptyAgain = "Encriptar de nuevo"
encryptionWarning = "¡Se detectó cifrado de contenido, pero aún están en texto plano!"
encryptionCommand = "Ejecute `npx @hugo-fixit/encrypt` después de la compilación para cifrarlos realmente."
[single.disclaimerMessage]
ai = "Este artículo fue generado por IA. Por favor, verifique la información de forma independiente."
repost = "Este artículo es un repost. Por favor, visite la fuente original para más información."
original = "Este es el contenido original del autor."
relatedContent = "Contenido relacionado"
[single.includedIn]
+272
View File
@@ -0,0 +1,272 @@
# Translations for Persian
# ترجمه به فارسی
# https://gohugo.io/content-management/multilingual/#translation-of-strings
# === Init ===
[init]
hugoVersionError = "نسخه Hugo بسیار پایین است.\n\nنسخه فعلی Hugo {{ .Current }} است و حداقل نسخه پشتیبانی‌شده برای FixIt {{ .Minimal }} می‌باشد.\n\nاگر Hugo را روی رایانه شخصی خود اجرا می‌کنید، برای راهنمای ارتقا به https://gohugo.io/getting-started/installing/#upgrade-hugo مراجعه کنید.\n\nاگر از پلت‌فرم شخص ثالث استفاده می‌کنید، لطفاً نسخه Hugo را مطابق با آن پیکربندی کنید."
configurationError = "خطای پیکربندی\nشما هنوز پارامتر نسخه FixIt را به درستی پیکربندی نکرده‌اید. به https://fixit.lruihao.cn/docs/getting-started/configuration/params/ مراجعه کنید"
compatibilityError = "خطای سازگاری ({{ .From }} -> {{ .To }}):\nشما یک به‌روزرسانی ناسازگار دارید. به https://github.com/hugo-fixit/FixIt/releases مراجعه کنید"
devVersionWarn = "شما از نسخه توسعه FixIt استفاده می‌کنید. لطفاً از نسخه پایدار استفاده کنید.\nبه https://github.com/hugo-fixit/FixIt/releases مراجعه کنید"
devEnvWarn = "محیط فعلی «development» است. «سیستم نظرات»، «PWA»، «CDN»، «اثر انگشت» و «تحلیل‌ها» غیرفعال خواهند شد."
quicklyUpgrade = "ارتقاء سریع با دستور: "
# === Init ===
# === Base Layout ===
[baseof]
backToTop = "بازگشت به بالا"
viewComments = "مشاهده نظرات"
noscript = "این وبسایت با فعال بودن JavaScript بهتر عمل می‌کند."
# === Base Layout ===
# === Taxonomy ===
[archives]
other = "بایگانی"
[allSome]
other = "همه {{ .Some }}"
[category]
other = "دسته‌بندی"
[categories]
other = "دسته‌بندی‌ها"
[collection]
other = "مجموعه"
[collections]
other = "مجموعه‌ها"
[tag]
other = "برچسب"
[tags]
other = "برچسب‌ها"
[posts]
other = "نوشته‌ها"
# === Taxonomy ===
# === Section ===
[section]
recentlyUpdated = "به‌روزرسانی‌های اخیر"
[section.totalWordCount]
one = "مجموع یک کلمه"
other = "مجموع {{ .Count }} کلمه"
[section.archiveCounter]
one = "فقط یک مقاله"
other = "مجموعاً {{ .Count }} مقاله"
# === Section ===
# === Pagination ===
[pagination]
more = "بیشتر"
# === Pagination ===
# === Header ===
[header]
selectLanguage = "انتخاب زبان"
noTranslations = "ترجمه‌ای موجود نیست"
switchTheme = "تغییر پوسته"
# === Header ===
# === Footer ===
[footer]
poweredBySome = "قدرت‌گرفته از {{ .Hugo }} | پوسته - {{ .Theme }}"
siteUV = "مجموع بازدیدکنندگان"
sitePV = "مجموع بازدیدها"
siteRunning = "وبسایت در حال اجرا ..."
# === Footer ===
# === Comment ===
[comment]
valinePlaceholder = "نظر شما ..."
# === Comment ===
# === Assets ===
[assets]
search = "جستجو"
searchPlaceholder = "جستجوی عناوین یا محتوا ..."
searchIn = "جستجو در {{ . }}"
searchBy = "جستجو بر اساس"
gotoResultsPage = "رفتن به صفحه نتایج جستجو ..."
clear = "پاک کردن"
cancel = "لغو"
navigate = "پیمایش"
select = "انتخاب"
close = "بستن"
refresh = "بازخوانی"
noResultsFound = "نتیجه‌ای یافت نشد"
copyToClipboard = "کپی در کلیپ‌بورد"
copyText = "کپی"
copiedText = "کپی شد"
toggleLineNumbers = "نمایش/مخفی کردن شماره خطوط"
toggleLineWrap = "نمایش/مخفی کردن پیچش کد"
toggleCodeEditable = "قابل ویرایش کردن بلوک کد"
downloadCode = "دانلود کد"
expandCode = "باز کردن یا بستن بلوک کد"
fullscreen = "تمام‌صفحه"
exitFullscreen = "خروج از تمام‌صفحه"
cookieconsentMessage = "این وبسایت از کوکی‌ها برای بهبود تجربه شما استفاده می‌کند."
cookieconsentDismiss = "متوجه شدم!"
cookieconsentLink = "اطلاعات بیشتر"
# === Assets ===
# === Share ===
[shareOn]
other = "اشتراک‌گذاری در"
# === Share ===
# === Single Post ===
[single]
contents = "فهرست مطالب"
navigation = "ناوبری"
disclaimer = "بیانیه نویسنده: "
pin = "سنجاق کردن به بالا"
repost = "بازنشر"
publishedOnDate = "منتشر شده در {{ .Date }}"
views = "بازدید"
comments = "نظرات"
author = "نویسنده"
updatedOnDate = "به‌روزرسانی شده در {{ .Date }}"
readMarkdown = "خواندن Markdown"
viewSource = "مشاهده سورس"
editThisPage = "ویرایش این صفحه"
reportIssue = "گزارش مشکل"
openInEditor = "باز کردن در ویرایشگر"
back = "بازگشت"
home = "خانه"
readMore = "ادامه مطلب"
expirationReminder = "این مقاله آخرین بار در {{ .Date }} به‌روزرسانی شده است و ممکن است محتوای آن قدیمی باشد."
encryptedAbstract = "این مقاله رمزنگاری شده است، بنابراین محتوای خام آن قابل مشاهده نیست!"
print = "چاپ"
encryptedMessage = "لطفاً رمز عبور را وارد کنید"
password = "رمز عبور"
enterBtn = "ورود"
encryptyAgain = "رمزنگاری مجدد"
encryptionWarning = "رمزنگاری محتوا شناسایی شد، اما هنوز به صورت متن ساده هستند!"
[single.disclaimerMessage]
ai = "این مقاله توسط هوش مصنوعی تولید شده است. لطفاً اطلاعات را به طور مستقل تأیید کنید."
repost = "این مقاله یک بازنشر است. لطفاً برای اطلاعات بیشتر به منبع اصلی مراجعه کنید."
original = "این محتوای اصلی نویسنده است."
encryptionCommand = "پس از ساخت، دستور `npx @hugo-fixit/encrypt` را اجرا کنید تا واقعاً رمزنگاری شوند."
relatedContent = "مطالب مرتبط"
[single.includedIn]
categories = "قرار گرفته در {{ .Categories }}"
collections = "قرار گرفته در {{ .Collections }}"
both = "قرار گرفته در {{ .Categories }} و {{ .Collections }}"
[single.wordCount]
one = "یک کلمه"
other = "{{ .Count }} کلمه"
[single.fuzzyWordCount]
other = "حدود {{ .Count }} کلمه"
[single.readingTime]
one = "یک دقیقه"
other = "{{ .Count }} دقیقه"
[single.reward]
donate = "حمایت مالی"
wechatpay = "WeChat Pay"
alipay = "Alipay"
paypal = "PayPal"
bitcoin = "Bitcoin"
# === Single Post ===
# === Error Pages ===
[pageNotFound]
other = "صفحه یافت نشد"
[pageNotFoundText]
other = "صفحه‌ای که به دنبال آن هستید وجود ندارد. متأسفیم."
# === Error Pages ===
# === Offline ===
[offlineTitle]
other = "آفلاین"
[offlineText]
other = "شما به اینترنت متصل نیستید، فقط صفحات ذخیره‌شده در دسترس خواهند بود."
# === Offline ===
# === Service Worker ===
[serviceWorker]
updateTitle = "به‌روزرسانی موجود است"
updateText = "نسخه جدیدی از این سایت موجود است."
# === Service Worker ===
# === Link Redirection ===
[linkRedirection]
title = "اعلامیه تغییر مسیر"
message = "شما در حال ترک {{ .Title }} هستید، لطفاً از امنیت حساب و دارایی خود اطمینان حاصل کنید."
confirm = "ادامه بازدید"
# === Link Redirection ===
# === Alert ===
[alert]
note = "توجه"
tip = "نکته"
important = "مهم"
warning = "هشدار"
caution = "احتیاط"
# === Alert ===
# === Task List ===
[taskList]
x = "تیک‌خورده"
" " = "بدون تیک"
"/" = "در حال انجام"
"-" = "لغو شده"
"<" = "برنامه‌ریزی شده"
">" = "برنامه‌ریزی مجدد شده"
"!" = "مهم"
"!x" = "مهم تیک‌خورده"
"?" = "سوال"
# === Task List ===
# === Admonition ===
[admonition]
note = "توجه"
abstract = "چکیده"
info = "اطلاعات"
todo = "انجام دادنی"
tip = "نکته"
success = "موفقیت"
question = "سوال"
warning = "هشدار"
failure = "شکست"
danger = "خطر"
bug = "خطا"
example = "مثال"
quote = "نقل‌قول"
# === Admonition ===
# === Version ===
[version]
new = "جدید"
changed = "تغییر یافته"
deleted = "حذف شده"
deprecated = "منسوخ شده"
# === Version ===
# === Diagram ===
[diagram]
zoomIn = "بزرگ‌نمایی"
zoomOut = "کوچک‌نمایی"
reset = "بازنشانی"
download = "دانلود SVG"
# === Diagram ===
# === Tabs ===
[tabs]
diagram = "نمودار"
code = "کد"
# === Tabs ===
+9 -2
View File
@@ -5,7 +5,6 @@
# === Init ===
[init]
hugoVersionError = "La version de Hugo est trop ancienne.\n\nLa version actuelle de Hugo est {{ .Current }}, la version minimale requise pour FixIt est {{ .Minimal }}.\n\nSi vous utilisez Hugo sur votre ordinateur, consultez le guide de mise à niveau à l'adresse https://gohugo.io/getting-started/installing/#upgrade-hugo.\n\nSi vous déployez sur une plateforme tierce, veuillez configurer la version de Hugo en conséquence."
hugoExtendedWarn = "La version étendue de Hugo est nécessaire pour la prise en charge de SCSS."
configurationError = "Erreur de configuration\nVous n'avez pas configuré la version de FixIt correctement. Voir https://fixit.lruihao.cn/docs/getting-started/configuration/params/?lang=french"
compatibilityError = "Erreur de compatibilité ({{ .From }} -> {{ .To }}):\nVous avez une mise à jour incompatible. Voir https://github.com/hugo-fixit/FixIt/releases"
devVersionWarn = "Vous utilisez une version de développement de FixIt. Veuillez considérer l'utilisation d'une version stable.\nVoir https://github.com/hugo-fixit/FixIt/releases"
@@ -70,7 +69,7 @@ more = "Plus"
# === Header ===
[header]
selectLanguage = "Choisir la langue"
noMoretTranslations = "Plus de traductions"
noTranslations = "Aucune traduction"
switchTheme = "Changer de Thème"
# === Header ===
@@ -124,6 +123,8 @@ other = "Partager via"
# === Single Post ===
[single]
contents = "Contenus"
navigation = "Navigation"
disclaimer = "Avertissement : "
pin = "Épingler en haut"
repost = "Reposter"
publishedOnDate = "publié le {{ .Date }}"
@@ -141,12 +142,18 @@ home = "Accueil"
readMore = "En savoir plus"
expirationReminder = "Cet article a été mis à jour pour la dernière fois le {{ .Date }}, son contenu est peut-être obsolète."
encryptedAbstract = "Cet article a été chiffré, son contenu n'est donc pas lisible!"
print = "Imprimer"
encryptedMessage = "Entrer le mot de passe"
password = "Mot de passe"
enterBtn = "Entrer"
encryptyAgain = "Chiffrer à nouveau"
encryptionWarning = "Chiffrement de contenu détecté, mais ils sont toujours en texte clair !"
encryptionCommand = "Exécutez `npx @hugo-fixit/encrypt` après la compilation pour les chiffrer réellement."
[single.disclaimerMessage]
ai = "Cet article a été généré par une IA. Veuillez vérifier les informations de manière indépendante."
repost = "Cet article est un repost. Veuillez visiter la source originale pour plus d'informations."
original = "Ceci est le contenu original de l'auteur."
relatedContent = "Contenu lié"
[single.includedIn]
+9 -2
View File
@@ -5,7 +5,6 @@
# === Init ===
[init]
hugoVersionError = "Hugo संस्करण बहुत पुराना है।\n\nवर्तमान में उपयोग किया जा रहा Hugo संस्करण {{ .Current }} है, जबकि FixIt के लिए न्यूनतम आवश्यक संस्करण {{ .Minimal }} है।\n\nयदि आप अपने कंप्यूटर पर Hugo का उपयोग कर रहे हैं, तो कृपया अपग्रेड गाइड देखें: https://gohugo.io/getting-started/installing/#upgrade-hugo\n\nयदि आप किसी तृतीय-पक्ष प्लेटफ़ॉर्म पर तैनात कर रहे हैं, तो कृपया Hugo संस्करण को तदनुसार कॉन्फ़िगर करें। "
hugoExtendedWarn = "SCSS समर्थन के लिए Hugo Extended संस्करण आवश्यक है।"
configurationError = "कन्फ़िग्यरेशन त्रुटि \nआपने फिक्सइट संस्करण पैरामीटर को सही ढंग से कॉन्फ़िगर नहीं किया है।. यह देखें: https://fixit.lruihao.cn/docs/getting-started/configuration/params/"
compatibilityError = "संगतता त्रुटि ({{ .From }} -> {{ .To }}):\nआपके पास एक असंगत अपडेट है. यह देखें: https://github.com/hugo-fixit/FixIt/releases"
devVersionWarn = "आप फिक्सइट के डिवेलपर संस्करण का उपयोग कर रहे हैं। कृपया एक स्थिर संस्करण का उपयोग करने पर विचार करें।\nयह देखें: https://github.com/hugo-fixit/FixIt/releases"
@@ -71,7 +70,7 @@ more = "और देखें"
# === Header ===
[header]
selectLanguage = "भाषा चुने"
noMoretTranslations = "कोई और अनुवाद नहीं"
noTranslations = "कोई अनुवाद नहीं"
switchTheme = "थीम बदलें"
# === Header ===
@@ -125,6 +124,8 @@ other = " शेयर करें"
# === Single Post ===
[single]
contents = "सामग्री"
navigation = "नेविगेशन"
disclaimer = "लेखक का बयान: "
pin = "शीर्ष पर पिन करें"
repost = "दोबारा पोस्ट करें"
publishedOnDate = "{{ .Date }} पर प्रकाशित"
@@ -142,6 +143,7 @@ home = "घर"
readMore = "और पढ़ें"
expirationReminder = "यह लेख अंतिम बार {{ .Date }} पर अद्यतन किया गया था, सामग्री पुरानी हो सकती है."
encryptedAbstract = "यह लेख एन्क्रिप्ट किया गया है, इसलिए इसकी मूल सामग्री अदृश्य है!"
print = "प्रिंट"
encryptedMessage = "कृपया पासवर्ड दर्ज करें"
password = "पासवर्ड"
enterBtn = "दर्ज करें"
@@ -150,6 +152,11 @@ encryptionWarning = "सामग्री एन्क्रिप्शन क
encryptionCommand = "उन्हें वास्तव में एन्क्रिप्ट करने के लिए बिल्ड के बाद `npx @hugo-fixit/encrypt` चलाएं।"
relatedContent = "संबंधित सामग्री"
[single.disclaimerMessage]
ai = "यह लेख AI द्वारा उत्पन्न किया गया था। कृपया जानकारी को स्वतंत्र रूप से सत्यापित करें।"
repost = "यह लेख एक पुनर्प्रकाशन है। कृपया अधिक जानकारी के लिए मूल स्रोत पर जाएं।"
original = "यह लेखक की मूल सामग्री है।"
[single.includedIn]
categories = "{{ .Categories }} में शामिल"
collections = "{{ .Collections }} में शामिल"
+9 -2
View File
@@ -5,7 +5,6 @@
# === Init ===
[init]
hugoVersionError = "La versione di Hugo è troppo bassa.\n\nLa versione attuale di Hugo è {{ .Current }}, la versione minima supportata per FixIt è {{ .Minimal }}.\n\nSe stai eseguendo Hugo sul tuo computer, consulta https://gohugo.io/getting-started/installing/#upgrade-hugo per la guida all'aggiornamento.\n\nSe stai distribuendo su una piattaforma di terze parti, configura la versione di Hugo di conseguenza."
hugoExtendedWarn = "La versione Hugo Extended è necessaria per il supporto SCSS."
configurationError = "Errore di configurazione\nNon hai ancora configurato correttamente il parametro della versione di FixIt. Vedi https://fixit.lruihao.cn/docs/getting-started/configuration/params/"
compatibilityError = "Errore di compatibilità ({{ .From }} -> {{ .To }}):\nHai un aggiornamento incompatibile. Vedi https://github.com/hugo-fixit/FixIt/releases"
devVersionWarn = "Stai utilizzando una versione di sviluppo di FixIt. Si prega di considerare l'utilizzo di una versione stabile.\nVedi https://github.com/hugo-fixit/FixIt/releases"
@@ -70,7 +69,7 @@ more = "Più"
# === Header ===
[header]
selectLanguage = "Scegliere la lingua"
noMoretTranslations = "Non ci sono altre traduzioni"
noTranslations = "Nessuna traduzione"
switchTheme = "Cambiare il tema"
# === Header ===
@@ -124,6 +123,8 @@ other = "Condividi su"
# === Single Post ===
[single]
contents = "Contenuti"
navigation = "Navigazione"
disclaimer = "Avvertenza: "
pin = "Fissa in alto"
repost = "Ripubblica"
publishedOnDate = "pubblicato su {{ .Date }}"
@@ -141,12 +142,18 @@ home = "Home"
readMore = "Leggi di più"
expirationReminder = "Questo articolo è stato aggiornato l'ultima volta il {{ .Date }}, il contenuto potrebbe non essere aggiornato."
encryptedAbstract = "Questo articolo è stato crittografato, quindi il suo contenuto grezzo è invisibile!"
print = "Stampa"
encryptedMessage = "Per favore inserisci la password"
password = "Password"
enterBtn = "Entra"
encryptyAgain = "Crittografa di nuovo"
encryptionWarning = "Rilevata crittografia dei contenuti, ma sono ancora in testo in chiaro!"
encryptionCommand = "Eseguire `npx @hugo-fixit/encrypt` dopo la compilazione per crittograffarli effettivamente."
[single.disclaimerMessage]
ai = "Questo articolo è stato generato da un'IA. Si prega di verificare le informazioni in modo indipendente."
repost = "Questo articolo è un repost. Si prega di visitare la fonte originale per maggiori informazioni."
original = "Questo è il contenuto originale dell'autore."
relatedContent = "Contenuti correlati"
[single.includedIn]
+9 -2
View File
@@ -5,7 +5,6 @@
# === Init ===
[init]
hugoVersionError = "Hugo のバージョンが低すぎます。\n\n現在の Hugo バージョンは {{ .Current }} ですが、FixIt がサポートする最小バージョンは {{ .Minimal }} です。\n\n自分のコンピューターで Hugo を実行している場合は、https://gohugo.io/getting-started/installing/#upgrade-hugo でアップグレードガイドを参照してください。\n\nサードパーティプラットフォームにデプロイしている場合は、Hugo バージョンを適切に設定してください。"
hugoExtendedWarn = "SCSS サポートには Hugo Extended バージョンが必要です。"
configurationError = "設定ファイルエラー\nまだ FixIt のバージョンパラメータを正しく設定していません。 https://fixit.lruihao.cn/docs/getting-started/configuration/params/?lang=japanese を参照してください"
compatibilityError = "互換性エラー ({{ .From }} -> {{ .To }}):\n互換性のない更新が行われました。 https://github.com/hugo-fixit/FixIt/releases を参照してください"
devVersionWarn = "開発版の FixIt を使用しています。安定版の使用を検討してください。\n https://github.com/hugo-fixit/FixIt/releases を参照"
@@ -68,7 +67,7 @@ more = "もっと見る"
# === Header ===
[header]
selectLanguage = "言語を選択"
noMoretTranslations = "これ以上の翻訳はありません"
noTranslations = "翻訳なし"
switchTheme = "テーマを切り替え"
# === Header ===
@@ -122,6 +121,8 @@ other = "共有先"
# === Single Post ===
[single]
contents = "目次"
navigation = "ナビゲーション"
disclaimer = "著者声明:"
pin = "ピン留め"
repost = "再投稿"
publishedOnDate = "公開日 {{ .Date }}"
@@ -139,6 +140,7 @@ home = "ホーム"
readMore = "続きを読む"
expirationReminder = "この記事は {{ .Date }} に最終更新されました。内容が古くなっている可能性があります。"
encryptedAbstract = "この記事は暗号化されているため、元の内容は表示できません!"
print = "印刷"
encryptedMessage = "パスワードを入力してください"
password = "パスワード"
enterBtn = "入る"
@@ -147,6 +149,11 @@ encryptionWarning = "コンテンツの暗号化が検出されましたが、
encryptionCommand = "実際に暗号化するには、ビルド後に `npx @hugo-fixit/encrypt` を実行してください。"
relatedContent = "関連コンテンツ"
[single.disclaimerMessage]
ai = "この記事はAIによって生成されました。情報を独自に確認してください。"
repost = "この記事は転載です。詳細は元のソースをご覧ください。"
original = "この記事は作者のオリジナルコンテンツです。"
[single.includedIn]
categories = "カテゴリに収録:{{ .Categories }}"
collections = "コレクションに収録:{{ .Collections }}"
+9 -2
View File
@@ -5,7 +5,6 @@
# === Init ===
[init]
hugoVersionError = "Hugo 버전이 너무 낮습니다.\n\n현재 Hugo 버전은 {{ .Current }}이며, FixIt의 최소 지원 버전은 {{ .Minimal }}입니다.\n\n자신의 컴퓨터에서 Hugo를 실행 중이라면 https://gohugo.io/getting-started/installing/#upgrade-hugo 에서 업그레이드 가이드를 확인하세요.\n\n타사 플랫폼에 배포 중이라면 Hugo 버전을 적절히 설정해 주세요."
hugoExtendedWarn = "SCSS 지원을 위해 Hugo Extended 버전이 필요합니다."
configurationError = "구성 파일 오류\n아직 FixIt의 버전 매개변수를 올바르게 구성하지 않았습니다. https://fixit.lruihao.cn/docs/getting-started/configuration/params/?lang=korean 을 참조하세요."
compatibilityError = "호환성 오류 ({{ .From }} -> {{ .To }}):\n비호환 업데이트를 수행했습니다. https://github.com/hugo-fixit/FixIt/releases 를 참조하세요."
devVersionWarn = "현재 개발 버전의 FixIt을 사용 중입니다. 안정적인 버전을 사용하는 것이 좋습니다.\n자세한 내용은 https://github.com/hugo-fixit/FixIt/releases 를 참조하세요."
@@ -68,7 +67,7 @@ more = "더 보기"
# === Header ===
[header]
selectLanguage = "언어 선택"
noMoretTranslations = "더 이상 번역습니다"
noTranslations = "번역 없"
switchTheme = "테마 전환"
# === Header ===
@@ -122,6 +121,8 @@ other = "공유하기"
# === Single Post ===
[single]
contents = "목차"
navigation = "내비게이션"
disclaimer = "작성자 성명: "
pin = "고정"
repost = "재게시"
publishedOnDate = "발행일: {{ .Date }}"
@@ -139,6 +140,7 @@ home = "홈"
readMore = "더 읽기"
expirationReminder = "이 문서는 {{ .Date }}에 마지막으로 업데이트되었으며, 내용이 오래되었을 수 있습니다."
encryptedAbstract = "이 문서는 암호화되어 원본 내용을 볼 수 없습니다!"
print = "인쇄"
encryptedMessage = "비밀번호를 입력하세요"
password = "비밀번호"
enterBtn = "입장"
@@ -147,6 +149,11 @@ encryptionWarning = "콘텐츠 암호화가 감지되었지만 여전히 평문
encryptionCommand = "실제로 암호화하려면 빌드 후 `npx @hugo-fixit/encrypt`를 실행하세요."
relatedContent = "관련 콘텐츠"
[single.disclaimerMessage]
ai = "이 글은 AI에 의해 생성되었습니다. 정보를 독립적으로 확인하시기 바랍니다."
repost = "이 글은 전재 콘텐츠입니다. 자세한 내용은 원문을 방문하시기 바랍니다."
original = "이 글은 저자의 오리지널 콘텐츠입니다."
[single.includedIn]
categories = "{{ .Categories }}에 포함"
collections = "{{ .Collections }}에 포함"
+9 -2
View File
@@ -5,7 +5,6 @@
# === Init ===
[init]
hugoVersionError = "Wersja Hugo jest zbyt niska.\n\nAktualna wersja Hugo to {{ .Current }}, minimalna obsługiwana wersja dla FixIt to {{ .Minimal }}.\n\nJeśli uruchamiasz Hugo na własnym komputerze, zapoznaj się z przewodnikiem aktualizacji na stronie https://gohugo.io/getting-started/installing/#upgrade-hugo.\n\nJeśli wdrażasz na platformie zewnętrznej, skonfiguruj odpowiednio wersję Hugo."
hugoExtendedWarn = "Wersja Hugo Extended jest wymagana do obsługi SCSS."
configurationError = "Błąd konfiguracji\nNie skonfigurowałeś jeszcze poprawnie parametru wersji FixIt. Zobacz https://fixit.lruihao.cn/docs/getting-started/configuration/params/"
compatibilityError = "Błąd zgodności ({{ .From }} -> {{ .To }}):\nMasz niekompatybilną aktualizację. Zobacz https://github.com/hugo-fixit/FixIt/releases"
devVersionWarn = "Używasz wersji deweloperskiej FixIt. Proszę rozważyć użycie stabilnej wersji.\nZobacz https://github.com/hugo-fixit/FixIt/releases"
@@ -70,7 +69,7 @@ more = "Więcej"
# === Header ===
[header]
selectLanguage = "Wybierz język"
noMoretTranslations = "Brak dalszych tłumaczeń"
noTranslations = "Brak tłumaczeń"
switchTheme = "Przełącz schemat"
# === Header ===
@@ -124,6 +123,8 @@ other = "Udostępnij na"
# === Single Post ===
[single]
contents = "Spis treści"
navigation = "Nawigacja"
disclaimer = "Ostrzeżenie: "
pin = "Przypnij na górze"
repost = "Prześlij ponownie"
publishedOnDate = "opublikowano {{ .Date }}"
@@ -141,12 +142,18 @@ home = "Strona główna"
readMore = "Czytaj więcej"
expirationReminder = "Ten artykuł był ostatnio aktualizowany {{ .Date }}, jego treść może być nieaktualna."
encryptedAbstract = "Ten artykuł został zaszyfrowany, więc jego surowa treść jest niewidoczna!"
print = "Drukuj"
encryptedMessage = "Proszę wprowadzić hasło"
password = "Hasło"
enterBtn = "Wejdź"
encryptyAgain = "Zaszyfruj ponownie"
encryptionWarning = "Wykryto szyfrowanie treści, ale nadal są w postaci zwykłego tekstu!"
encryptionCommand = "Uruchom `npx @hugo-fixit/encrypt` po kompilacji, aby je faktycznie zaszyfrować."
[single.disclaimerMessage]
ai = "Ten artykuł został wygenerowany przez AI. Proszę samodzielnie zweryfikować informacje."
repost = "Ten artykuł jest repostem. Proszę odwiedzić oryginalne źródło, aby uzyskać więcej informacji."
original = "To jest oryginalna treść autora."
relatedContent = "Powiązane treści"
[single.includedIn]
+9 -2
View File
@@ -5,7 +5,6 @@
# === Init ===
[init]
hugoVersionError = "A versão do Hugo é muito baixa.\n\nA versão atual do Hugo é {{ .Current }}, a versão mínima suportada pelo FixIt é {{ .Minimal }}.\n\nSe você está executando o Hugo em seu computador, consulte https://gohugo.io/getting-started/installing/#upgrade-hugo para obter um guia de atualização.\n\nSe você está implantando em uma plataforma de terceiros, configure a versão do Hugo adequadamente."
hugoExtendedWarn = "A versão Hugo Extended é necessária para o suporte a SCSS."
configurationError = "Erro de configuração\nVocê ainda não configurou o parâmetro da versão do FixIt corretamente. Consulte https://fixit.lruihao.cn/docs/getting-started/configuration/params/"
compatibilityError = "Erro de compatibilidade ({{ .From }} -> {{ .To }}):\nVocê tem uma atualização incompatível. Consulte https://github.com/hugo-fixit/FixIt/releases"
devVersionWarn = "Você está usando a versão de desenvolvedor do FixIt. Por favor, use uma versão estável. \nConsulte https://github.com/hugo-fixit/FixIt/releases"
@@ -71,7 +70,7 @@ more = "Mais"
# === Header ===
[header]
selectLanguage = "Selecione o idioma"
noMoretTranslations = "Não há mais traduções"
noTranslations = "Sem traduções"
switchTheme = "Trocar tema"
# === Header ===
@@ -125,6 +124,8 @@ other = "Compartilhar em"
# === Single Post ===
[single]
contents = "Conteúdos"
navigation = "Navegação"
disclaimer = "Aviso: "
pin = "Fixar no topo"
repost = "Repostar"
publishedOnDate = "publicado em {{ .Date }}"
@@ -142,11 +143,17 @@ home = "Home"
readMore = "Leia mais"
expirationReminder = "Este artigo foi atualizado pela última vez em {{ .Date }}, o conteúdo pode estar desatualizado."
encryptedAbstract = "Este artigo foi encriptado, então seu contéudo bruto é invisível!"
print = "Imprimir"
encryptedMessage = "Por favor, insira a senha"
password = "Senha"
enterBtn = "Entrar"
encryptyAgain = "Encripte novamente"
encryptionWarning = "Criptografia de conteúdo detectada, mas ainda estão em texto plano!"
[single.disclaimerMessage]
ai = "Este artigo foi gerado por IA. Por favor, verifique as informações de forma independente."
repost = "Este artigo é um repost. Por favor, visite a fonte original para mais informações."
original = "Este é o conteúdo original do autor."
encryptionCommand = "Execute `npx @hugo-fixit/encrypt` após a compilação para realmente criptografá-los."
relatedContent = "Conteúdo relacionado"
+9 -2
View File
@@ -5,7 +5,6 @@
# === Init ===
[init]
hugoVersionError = "Versiunea Hugo este prea veche.\n\nVersiunea curentă Hugo este {{ .Current }}, versiunea minimă compatibilă cu FixIt este {{ .Minimal }}.\n\nDacă rulați Hugo pe propriul computer, consultați https://gohugo.io/getting-started/installing/#upgrade-hugo pentru ghidul de actualizare.\n\nDacă implementați pe o platformă terță, configurați versiunea Hugo corespunzător."
hugoExtendedWarn = "Versiunea Hugo Extended este necesară pentru suportul SCSS."
configurationError = "Eroare de configurare\nNu ați configurat corect parametrul versiunii FixIt. Consultați https://fixit.lruihao.cn/docs/getting-started/configuration/params/"
compatibilityError = "Eroare de compatibilitate ({{ .From }} -> {{ .To }}):\nAveți o actualizare incompatibilă. Consultați https://github.com/hugo-fixit/FixIt/releases"
devVersionWarn = "Utilizați o versiune de dezvoltare a FixIt. Vă rugăm să luați în considerare utilizarea unei versiuni stabile.\nConsultați https://github.com/hugo-fixit/FixIt/releases"
@@ -70,7 +69,7 @@ more = "Mai mult"
# === Header ===
[header]
selectLanguage = "Selectare Limbă"
noMoretTranslations = "Nu mai sunt traduceri disponibile"
noTranslations = "Fără traduceri"
switchTheme = "Schimbare Temă"
# === Header ===
@@ -124,6 +123,8 @@ other = "Distribuie pe"
# === Single Post ===
[single]
contents = "Cuprins"
navigation = "Navigare"
disclaimer = "Notificare: "
pin = "Fixează în partea de sus"
repost = "Repostează"
publishedOnDate = "publicat la {{ .Date }}"
@@ -141,12 +142,18 @@ home = "Acasă"
readMore = "Citește mai mult"
expirationReminder = "Acest articol a fost actualizat ultima dată pe {{ .Date }}, conținutul poate fi depășit."
encryptedAbstract = "Acest articol a fost criptat, astfel încât conținutul său brut este invizibil!"
print = "Imprimare"
encryptedMessage = "Vă rugăm să introduceți parola"
password = "Parolă"
enterBtn = "Intră"
encryptyAgain = "Criptează din nou"
encryptionWarning = "Criptarea conținutului a fost detectată, dar sunt încă în text clar!"
encryptionCommand = "Rulați `npx @hugo-fixit/encrypt` după compilare pentru a le cripta efectiv."
[single.disclaimerMessage]
ai = "Acest articol a fost generat de AI. Vă rugăm să verificați informațiile în mod independent."
repost = "Acest articol este o repostare. Vă rugăm să vizitați sursa originală pentru mai multe informații."
original = "Acesta este conținutul original al autorului."
relatedContent = "Conținut înrudit"
[single.includedIn]
+9 -2
View File
@@ -5,7 +5,6 @@
# === Init ===
[init]
hugoVersionError = "Версия Hugo слишком низкая.\n\nТекущая версия Hugo — {{ .Current }}, минимальная поддерживаемая версия для FixIt — {{ .Minimal }}.\n\nЕсли вы запускаете Hugo на своём компьютере, ознакомьтесь с руководством по обновлению по адресу https://gohugo.io/getting-started/installing/#upgrade-hugo.\n\nЕсли вы развёртываете на сторонней платформе, настройте версию Hugo соответствующим образом."
hugoExtendedWarn = "Для поддержки SCSS необходима версия Hugo Extended."
configurationError = "Ошибка конфигурации\nВы еще не настроили параметр версии FixIt правильно. См. https://fixit.lruihao.cn/docs/getting-started/configuration/params/?lang=russian"
compatibilityError = "Ошибка совместимости ({{ .From }} -> {{ .To }}):\nУ вас есть несовместимое обновление. См. https://github.com/hugo-fixit/FixIt/releases"
devVersionWarn = "Вы используете версию разработки FixIt. Пожалуйста, рассмотрите возможность использования стабильной версии.\nСм. https://github.com/hugo-fixit/FixIt/releases"
@@ -70,7 +69,7 @@ more = "Больше"
# === Header ===
[header]
selectLanguage = "Выбор Языка"
noMoretTranslations = "Нет больше переводов"
noTranslations = "Нет переводов"
switchTheme = "Сменить Тему"
# === Header ===
@@ -124,6 +123,8 @@ other = "Поделиться в"
# === Single Post ===
[single]
contents = "Содержание"
navigation = "Навигация"
disclaimer = "Заявление автора: "
pin = "Закрепить наверху"
repost = "Перепостить"
publishedOnDate = "Опубликовано {{ .Date }}"
@@ -141,12 +142,18 @@ home = "Домой"
readMore = "Читать больше"
expirationReminder = "Эта статья последний раз обновлялась {{ .Date }}, содержание может быть устаревшим."
encryptedAbstract = "Эта статья была зашифрована, поэтому ее исходное содержание невидимо!"
print = "Печать"
encryptedMessage = "Пожалуйста, введите пароль"
password = "арготизм"
enterBtn = "Войти"
encryptyAgain = "Зашифровать снова"
encryptionWarning = "Обнаружено шифрование контента, но он всё ещё в открытом виде!"
encryptionCommand = "Запустите `npx @hugo-fixit/encrypt` после сборки, чтобы фактически зашифровать их."
[single.disclaimerMessage]
ai = "Эта статья была сгенерирована ИИ. Пожалуйста, проверьте информацию самостоятельно."
repost = "Эта статья является репостом. Пожалуйста, посетите оригинальный источник для получения дополнительной информации."
original = "Это оригинальный контент автора."
relatedContent = "Связанный контент"
[single.includedIn]

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