mirror of
https://github.com/hugo-fixit/FixIt.git
synced 2026-08-24 15:28:57 +00:00
feat(File Tree): add file-tree shortcode support (#685)
* feat(File Tree): add `file-tree` shortcode support * feat(file-tree): add ignoreList parameter to file-tree shortcode * feat(file-tree): enhance file-tree shortcode with ignoreList and folderSlash options * feat(file-tree): enhance file-tree shortcode to support data mode * feat(file-tree): enhance file-tree shortcode to support file mode * feat(file-tree): improve content parsing in file-tree shortcode * feat(file-tree): improve root path validation and error handling in filesystem mode * test(file-tree): add unit tests for `file-tree` shortcode * feat(file-tree): add file-tree code block rendering support * refactor(file-tree): extract filesystem scanning to get-file-tree partial Move directory traversal and root path validation to a separate partial function, consolidating all filesystem-related logic in one place. This simplifies the shortcode implementation and ensures a unified data format for rendering. * docs(readme): extend code fence and shortcode support for file tree in documentation * feat(file-tree): add fullRootName parameter for root path display in file tree * feat(file-tree): add language parameter to get-file-tree function * feat(file-tree): add highlightList parameter for file-tree shortcode * perf(file-tree): add level param for get-file-tree function to descend only level directories deep
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
{{- /*
|
||||
Renders an interactive file tree structure from inline content, resources, data files, or filesystem
|
||||
See https://fixit.lruihao.cn/documentation/content-management/shortcodes/extended/file-tree/
|
||||
|
||||
@param {string} [path="/"] - The path to scan in filesystem (relative to project root or contentDir)
|
||||
@param {int} [level=1] - The expand level of the tree (expand all: -1, collapse all: 0)
|
||||
@param {boolean} [folderSlash=false] - Whether to append a trailing "/" to folder names.
|
||||
@param {string} [file] - The path of a data file in page resources or assets. (JSON/YAML/TOML)
|
||||
@param {string} [data] - The name of the data file in data/filetree/ directory. (JSON/YAML/TOML)
|
||||
@param {string} [ignoreList=""] - List of file or folder names to ignore, separated by commas
|
||||
@param {string} [highlightList=""] - List of file or folder names to highlight, separated by commas
|
||||
@param {boolean} [fullRootName=false] - Whether to use the full root path as the root name when scanning filesystem
|
||||
|
||||
Priority order (highest to lowest):
|
||||
1. Inline content (shortcode body) - Parse tree data from shortcode body
|
||||
2. Resources files (file parameter) - Read data file from page bundle or asset
|
||||
3. Data files (data parameter) - Load data file from data/filetree/ directory
|
||||
4. Actual Filesystem (path parameter) - Scan actual directory structure (default)
|
||||
|
||||
Fallback mechanism: If the current mode fails (e.g., file not found, invalid format),
|
||||
the shortcode will automatically fall back to the next available mode in the priority order.
|
||||
|
||||
@example
|
||||
{{< file-tree "content" 2 />}}
|
||||
{{< file-tree path="content" level=2 folderSlash=true />}}
|
||||
{{< file-tree file="data/example.yml" />}}
|
||||
{{< file-tree data="example" />}}
|
||||
{{< file-tree >}}
|
||||
- name: my-project
|
||||
type: dir
|
||||
children:
|
||||
- name: src
|
||||
type: dir
|
||||
- name: package.json
|
||||
type: file
|
||||
{{< /file-tree >}}
|
||||
|
||||
Data format note: YAML and JSON support direct array format, while TOML requires a root key 'filetree' due to format limitations.
|
||||
Example TOML structure:
|
||||
```file-tree
|
||||
[[filetree]]
|
||||
name = "src"
|
||||
type = "dir"
|
||||
|
||||
[[filetree.children]]
|
||||
name = "index.ts"
|
||||
type = "file"
|
||||
|
||||
[[filetree]]
|
||||
name = "README.md"
|
||||
type = "file"
|
||||
```
|
||||
*/ -}}
|
||||
|
||||
{{- $config := dict | merge .Page.Params.filetree | merge .Site.Params.filetree -}}
|
||||
{{- $root := cond .IsNamedParams (.Get "path") (.Get 0) | default "/" -}}
|
||||
{{- $level := cond .IsNamedParams (.Get "level") (.Get 1) -}}
|
||||
{{- $config = cond ((eq $level 0) | or $level) (dict "level" $level | merge $config) $config -}}
|
||||
{{- $level = cond (isset $config "level") ($config.level | int) 1 -}}
|
||||
{{- $folderSlash := cond .IsNamedParams (.Get "folderSlash") (.Get 2) | default $config.folderslash | default false -}}
|
||||
{{- $fileName := .Get "file" -}}
|
||||
{{- $dataName := .Get "data" -}}
|
||||
{{- $supportExts := slice ".yml" ".yaml" ".json" ".toml" -}}
|
||||
{{- $ignoreList := union (apply (split (.Get "ignoreList" | default "") ",") "trim" "." " ") $config.ignorelist -}}
|
||||
{{- $highlightList := apply (split (.Get "highlightList" | default "") ",") "trim" "." " " -}}
|
||||
{{- $fullRootName := .Get "fullRootName" | default false -}}
|
||||
|
||||
{{- /* Shortcode body */ -}}
|
||||
{{- $content := strings.TrimSpace .Inner | default "" -}}
|
||||
{{- /* File Data */ -}}
|
||||
{{- if $fileName | and (eq $content "") -}}
|
||||
{{- $ext := path.Ext $fileName | lower -}}
|
||||
{{- if in $supportExts $ext -}}
|
||||
{{- with dict "Path" $fileName "Resources" $.Page.Resources | partial "function/resource.html" }}
|
||||
{{- $content = .Content -}}
|
||||
{{- else -}}
|
||||
{{- warnidf "warning-file-tree" "[%s]: no such data file: %s. See %s" $.Name $fileName $.Position -}}
|
||||
{{- end -}}
|
||||
{{- else -}}
|
||||
{{- warnidf "warning-file-tree" "[%s]: Unsupported file format '%s'. Use %s. See %s" $.Name $ext (delimit $supportExts ", " " or ") $.Position -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- /* Parse structured data from content or file */ -}}
|
||||
{{- $treeData := slice -}}
|
||||
{{- with $content -}}
|
||||
{{- $treeData = . | unmarshal -}}
|
||||
{{- if reflect.IsMap $treeData -}}
|
||||
{{- $treeData = $treeData.filetree -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- /* Site Data: load from data/filetree/ */ -}}
|
||||
{{- if $dataName | and (not $treeData) -}}
|
||||
{{- with index .Site.Data.filetree (printf "%v.%v" $dataName .Page.Language) | default (index .Site.Data.filetree $dataName) -}}
|
||||
{{- $treeData = . -}}
|
||||
{{- else -}}
|
||||
{{- $exts := delimit (apply $supportExts "trim" "." "\\.") "|" -}}
|
||||
{{- warnidf "warning-file-tree" "[%s]: Data file 'data/filetree/%s.{%s}' not found. See %s" $.Name $dataName $exts $.Position -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- /* Filesystem mode: scan directory structure */ -}}
|
||||
{{- if not $treeData -}}
|
||||
{{- /* Build structured tree data from filesystem */ -}}
|
||||
{{- $buildOptions := dict "root" $root "ignoreList" $ignoreList "deep" 0 "fullRootName" $fullRootName "lang" .Page.Language "log" false -}}
|
||||
{{- with partial "function/get-file-tree.html" $buildOptions -}}
|
||||
{{- $treeData = . -}}
|
||||
{{- else -}}
|
||||
{{- warnidf "warning-file-tree" "[%s]: The root path does not exist: %s. See %s" .Name $root .Position -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- /* Render the file tree */ -}}
|
||||
{{- $options := dict
|
||||
"items" $treeData
|
||||
"level" $level
|
||||
"folderSlash" $folderSlash
|
||||
"ignoreList" $ignoreList
|
||||
"highlightList" $highlightList
|
||||
-}}
|
||||
{{- partial "plugin/file-tree.html" $options -}}
|
||||
Reference in New Issue
Block a user