Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions apps/test/content/posts/tabs-comprehensive-test.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,3 +216,16 @@ type = "file"

{{% /tab %}}
{{< /tabs >}}

### MathJax inside tabs

{{< tabs >}}
{{% tab title="Inline" %}}
$c = \pm\sqrt{a^2 + b^2}$ and \(f(x)=\int_{-\infty}^{\infty} \hat{f}(\xi) e^{2 \pi i \xi x} d \xi\)
{{% /tab %}}
{{% tab title="Block" %}}
$$ x = {-b \pm \sqrt{b^2-4ac} \over 2a} $$

\[ f(a) = \frac{1}{2\pi i} \oint\frac{f(z)}{z-a}dz \]
{{% /tab %}}
{{< /tabs >}}
72 changes: 39 additions & 33 deletions assets/js/theme.js
Original file line number Diff line number Diff line change
Expand Up @@ -1613,44 +1613,50 @@ class FixIt {
initPrint() {
window.addEventListener('beforeprint', () => {
const $content = document.getElementById('content');
// revert code tabs to code blocks for better printing support
Util.forEach($content.querySelectorAll('.code-tabs'), ($codeTabs) => {
// restore action buttons to the active tab's code-header before reverting
const $actions = $codeTabs.querySelector('.tabs-actions');
const $activeBlock = $codeTabs.querySelector('.code-block.active');
if ($actions && $activeBlock) {
const $codeHeader = $activeBlock.querySelector('.code-header');
if ($codeHeader) {
Array.from($actions.children).forEach(btn => $codeHeader.appendChild(btn));
const printConfig = this.config.print || {};

if (printConfig.expandAdmonition) {
Util.forEach($content.querySelectorAll('.admonition'), ($el) => $el.classList.add('open'));
}
if (printConfig.expandCode) {
// revert code tabs to code blocks for better printing support
Util.forEach($content.querySelectorAll('.code-tabs'), ($codeTabs) => {
// restore action buttons to the active tab's code-header before reverting
const $actions = $codeTabs.querySelector('.tabs-actions');
const $activeBlock = $codeTabs.querySelector('.code-block.active');
if ($actions && $activeBlock) {
const $codeHeader = $activeBlock.querySelector('.code-header');
if ($codeHeader) {
Array.from($actions.children).forEach(btn => $codeHeader.appendChild(btn));
}
}
}
const $codeBlocks = $codeTabs.querySelectorAll('.code-block');
$codeBlocks.forEach(($codeBlock) => {
delete $codeBlock.dataset.tabInit;
$codeTabs.parentElement.insertBefore($codeBlock, $codeTabs);
const $codeBlocks = $codeTabs.querySelectorAll('.code-block');
$codeBlocks.forEach(($codeBlock) => {
delete $codeBlock.dataset.tabInit;
$codeTabs.parentElement.insertBefore($codeBlock, $codeTabs);
});
$codeTabs.parentElement.removeChild($codeTabs);
});
$codeTabs.parentElement.removeChild($codeTabs);
});
Util.forEach($content.querySelectorAll('.code-block'), ($el) => {
// line wrapping
$el.classList.add('line-wrapping');
// expand all code blocks
$el.classList.remove('is-collapsed');
// expand code preview
if ($el.querySelector('.code-expand-btn')) {
$el.classList.add('is-expanded');
}
});
FileTree.expandAll($content);
Util.forEach($content.querySelectorAll('.details'), ($el) => {
$el.classList.add('open');
});
Util.forEach($content.querySelectorAll('details'), ($el) => {
$el.setAttribute('open', '');
});
Util.forEach($content.querySelectorAll('.code-block'), ($el) => {
// line wrapping
$el.classList.add('line-wrapping');
// expand all code blocks
$el.classList.remove('is-collapsed');
// expand code preview
if ($el.querySelector('.code-expand-btn')) {
$el.classList.add('is-expanded');
}
});
}
if (printConfig.expandDetails) {
Util.forEach($content.querySelectorAll('details'), ($el) => $el.setAttribute('open', ''));
}
for (let event of this.beforeprintEventSet) {
event();
}
if (printConfig.expandFileTree) {
FileTree.expandAll($content);
}
}, false);

window.addEventListener('afterprint', () => {
Expand Down
11 changes: 11 additions & 0 deletions hugo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -1178,6 +1178,17 @@ folderSlash = false
# list of file or folder names to ignore
ignoreList = []

# FixIt 0.4.5 | NEW Print config
[params.print]
# whether to expand all admonitions before printing
expand_admonition = true
# whether to expand all code blocks and code tabs before printing
expand_code = true
# whether to expand all details elements before printing
expand_details = true
# whether to expand all file trees before printing
expand_file_tree = false

# FixIt 0.3.12 | NEW Custom partials config
# Custom partials must be stored in the /layouts/_partials/ directory.
# Depends on open custom blocks https://fixit.lruihao.cn/references/blocks/
Expand Down
4 changes: 4 additions & 0 deletions layouts/_partials/assets.html
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@

{{- /* Cell Tooltip */ -}}
{{- if eq .Site.Params.tooltip true -}}
{{- /* [todo] 临时可行性验证,需要寻找一个更稳定的替代品(Floating UI) */ -}}
{{- $source := $cdn.cellTooltipJS | default "lib/cell-tooltip/cell-tooltip.umd.js" -}}
{{- dict "Source" $source "Fingerprint" $fingerprint "Defer" true | dict "Page" . "Data" | partial "store/script.html" -}}
{{- $config = dict "tooltip" true | merge $config -}}
Expand Down Expand Up @@ -307,6 +308,9 @@
{{- end -}}
{{- end -}}

{{- /* Print */ -}}
{{- $config = partial "function/snake2camel.html" .Site.Params.print | dict "print" | merge $config -}}

{{- /* PostChat */ -}}
{{- partial "plugin/post-chat-ai.html" . -}}

Expand Down
91 changes: 91 additions & 0 deletions layouts/_partials/function/snake2camel.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
{{- /*
Convert snake_case config keys to camelCase recursively.

This is mainly used to avoid problems caused by Hugo's case-insensitive config key parsing.
Keep config keys in snake_case, then convert them here for stable access in templates and JS.

@param {map} . - The input map/object with snake_case keys
@return {map} A new map with camelCase keys, or the input if it's not a map

@example
// Simple Map conversion
Input: dict "code_block" true "max_shown_lines" 10 "line_nos" false
Output: dict "codeBlock" true "maxShownLines" 10 "lineNos" false

@example
// Nested Map conversion
Input: dict "code_block" (dict "enable_wrapper" true)
Output: dict "codeBlock" (dict "enableWrapper" true)

@example
// Array of Maps conversion
Input: slice (dict "user_name" "John") (dict "user_age" 30)
Output: slice (dict "userName" "John") (dict "userAge" 30)

@example
// Practical usage in templates
{{- $siteParams := partial "function/snake2camel.html" .Site.Params }}
// Now access parameters with camelCase: $siteParams.codeBlock.enableWrapper
// [todo] refactor all config to use snake_case in Hugo config files, and camelCase in templates and JS (v1.0 breaking change)
*/ -}}
{{- $input := . -}}
{{- $output := dict -}}

{{- if reflect.IsMap $input -}}
{{- /* Process map: iterate through all key-value pairs */ -}}
{{- range $key, $value := $input -}}
{{- /*
Convert key from snake_case to camelCase
Example: "max_shown_lines" -> "maxShownLines"
Strategy: split by "_", capitalize first letter of each part (except first), then concatenate
*/ -}}
{{- $parts := split $key "_" -}}
{{- $newKey := index $parts 0 -}}
{{- range $i, $part := $parts -}}
{{- if gt $i 0 -}}
{{- /* Capitalize first letter, preserve the rest */ -}}
{{- $first := upper (substr $part 0 1) -}}
{{- $rest := substr $part 1 -}}
{{- $newKey = printf "%s%s%s" $newKey $first $rest -}}
{{- end -}}
{{- end -}}

{{- /*
Recursively process value based on its type
- For nested maps: recursively convert all nested keys
- For arrays: process each map element in the array
- For scalar values: keep as-is
*/ -}}
{{- $newValue := $value -}}
{{- if reflect.IsMap $value -}}
{{- $newValue = partial "function/snake2camel.html" $value -}}
{{- else if reflect.IsSlice $value -}}
{{- $newValue = slice -}}
{{- range $item := $value -}}
{{- if reflect.IsMap $item -}}
{{- $newValue = $newValue | append (partial "function/snake2camel.html" $item) -}}
{{- else -}}
{{- $newValue = $newValue | append $item -}}
{{- end -}}
{{- end -}}
{{- end -}}

{{- /* Add the converted key-value pair to output */ -}}
{{- $output = merge $output (dict $newKey $newValue) -}}
{{- end -}}
{{- return $output -}}
{{- else if reflect.IsSlice $input -}}
{{- /* Process array: recursively convert each map element */ -}}
{{- $output := slice -}}
{{- range $item := $input -}}
{{- if reflect.IsMap $item -}}
{{- $output = $output | append (partial "function/snake2camel.html" $item) -}}
{{- else -}}
{{- $output = $output | append $item -}}
{{- end -}}
{{- end -}}
{{- return $output -}}
{{- else -}}
{{- /* Return scalar values unchanged */ -}}
{{- return $input -}}
{{- end -}}
Loading