mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-05-20 11:53:48 +00:00
Updated Wiki content
70
.github/workflows/deploy-wiki.yml
vendored
Normal file
70
.github/workflows/deploy-wiki.yml
vendored
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
name: Deploy Wiki to orca-website
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-and-deploy:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout OrcaSlicer_WIKI repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 1
|
||||||
|
|
||||||
|
- name: Set up Python
|
||||||
|
uses: actions/setup-python@v5
|
||||||
|
with:
|
||||||
|
python-version: '3.x'
|
||||||
|
|
||||||
|
- name: Install mkdocs
|
||||||
|
run: pip install mkdocs
|
||||||
|
|
||||||
|
- name: Build wiki content
|
||||||
|
run: |
|
||||||
|
chmod +x build.sh
|
||||||
|
./build.sh -d
|
||||||
|
|
||||||
|
- name: Generate GitHub App token
|
||||||
|
id: app-token
|
||||||
|
uses: actions/create-github-app-token@v1
|
||||||
|
with:
|
||||||
|
app-id: ${{ secrets.APP_ID }}
|
||||||
|
private-key: ${{ secrets.APP_PRIVATE_KEY }}
|
||||||
|
owner: OrcaSlicer
|
||||||
|
repositories: orca-website
|
||||||
|
|
||||||
|
- name: Clone orca-website repository
|
||||||
|
run: |
|
||||||
|
git clone --depth 1 https://x-access-token:${{ steps.app-token.outputs.token }}@github.com/OrcaSlicer/orca-website.git orca-website
|
||||||
|
|
||||||
|
- name: Deploy wiki content
|
||||||
|
run: |
|
||||||
|
# Remove old wiki folder if it exists
|
||||||
|
rm -rf orca-website/wiki
|
||||||
|
|
||||||
|
# Copy new wiki content
|
||||||
|
cp -r wiki orca-website/wiki
|
||||||
|
|
||||||
|
# Configure git
|
||||||
|
cd orca-website
|
||||||
|
git config user.name "github-actions[bot]"
|
||||||
|
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||||
|
|
||||||
|
# Check if there are changes to commit
|
||||||
|
if git diff --quiet && git diff --staged --quiet; then
|
||||||
|
echo "No changes to deploy"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Stage, commit and push
|
||||||
|
git add wiki
|
||||||
|
git commit -m "Update wiki content from OrcaSlicer_WIKI
|
||||||
|
|
||||||
|
Source commit: ${{ github.sha }}
|
||||||
|
Triggered by: ${{ github.actor }}"
|
||||||
|
git push
|
||||||
|
|
||||||
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
wiki/
|
||||||
|
.DS_Store
|
||||||
182
build.sh
Executable file
182
build.sh
Executable file
@@ -0,0 +1,182 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Build script for OrcaSlicer WIKI using mkdocs
|
||||||
|
# Outputs HTML to the wiki/ folder
|
||||||
|
|
||||||
|
set -e # Exit on error
|
||||||
|
|
||||||
|
# Parse command-line arguments
|
||||||
|
DOWNLOAD_SVG=false
|
||||||
|
for arg in "$@"; do
|
||||||
|
case $arg in
|
||||||
|
--download-svg|-d)
|
||||||
|
DOWNLOAD_SVG=true
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
# Unknown option
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# Check for required dependencies
|
||||||
|
command -v mkdocs >/dev/null 2>&1 || { echo "Error: mkdocs is required but not installed."; exit 1; }
|
||||||
|
command -v python3 >/dev/null 2>&1 || { echo "Error: python3 is required but not installed."; exit 1; }
|
||||||
|
|
||||||
|
# python3 generate_nav.py --update
|
||||||
|
|
||||||
|
echo "Building documentation with mkdocs..."
|
||||||
|
|
||||||
|
# Clean previous build and prepare docs directory
|
||||||
|
rm -rf wiki
|
||||||
|
mkdir -p docs
|
||||||
|
|
||||||
|
# Copy all markdown files and directories to docs, excluding wiki and docs itself
|
||||||
|
# This creates a structure mkdocs can work with
|
||||||
|
echo "Preparing documentation structure..."
|
||||||
|
|
||||||
|
# Copy all directories and markdown files, excluding wiki, docs, and .git
|
||||||
|
rsync -av \
|
||||||
|
--exclude='wiki' \
|
||||||
|
--exclude='docs' \
|
||||||
|
--exclude='.git' \
|
||||||
|
--exclude='*.sh' \
|
||||||
|
--exclude='*.py' \
|
||||||
|
--exclude='*.yml' \
|
||||||
|
--exclude='*.yaml' \
|
||||||
|
--exclude='README.md' \
|
||||||
|
--exclude='Home.md' \
|
||||||
|
--exclude='.gitignore' \
|
||||||
|
--exclude='infill-analysis' \
|
||||||
|
. docs/ 2>/dev/null || {
|
||||||
|
# Fallback: manually copy directories and markdown files
|
||||||
|
echo "Using fallback copy method..."
|
||||||
|
# Copy root level markdown files, excluding Home.md and README.md
|
||||||
|
find . -maxdepth 1 -name "*.md" ! -name "README.md" ! -name "Home.md" -exec cp {} docs/ \;
|
||||||
|
# Copy all directories with markdown files
|
||||||
|
[ -d "images" ] && cp -r images docs/ 2>/dev/null || true
|
||||||
|
[ -d "calibration" ] && cp -r calibration docs/ 2>/dev/null || true
|
||||||
|
[ -d "developer-reference" ] && cp -r developer-reference docs/ 2>/dev/null || true
|
||||||
|
[ -d "general-settings" ] && cp -r general-settings docs/ 2>/dev/null || true
|
||||||
|
[ -d "material_settings" ] && cp -r material_settings docs/ 2>/dev/null || true
|
||||||
|
[ -d "print_prepare" ] && cp -r print_prepare docs/ 2>/dev/null || true
|
||||||
|
[ -d "print_settings" ] && cp -r print_settings docs/ 2>/dev/null || true
|
||||||
|
[ -d "printer_settings" ] && cp -r printer_settings docs/ 2>/dev/null || true
|
||||||
|
}
|
||||||
|
|
||||||
|
# Copy Home.md as index.md so mkdocs generates index.html at root level
|
||||||
|
# (Home.md was excluded from rsync, so copy it directly from source)
|
||||||
|
if [ -f "Home.md" ]; then
|
||||||
|
cp Home.md docs/index.md
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Convert GitHub image URLs to relative local paths in all markdown files
|
||||||
|
echo "Converting GitHub image URLs to local paths..."
|
||||||
|
|
||||||
|
# Download SVG icons if option is enabled
|
||||||
|
if [ "$DOWNLOAD_SVG" = true ]; then
|
||||||
|
# Create directory for OrcaSlicer main repo icons
|
||||||
|
mkdir -p docs/images/orcaslicer-icons
|
||||||
|
|
||||||
|
# Extract and download unique SVG icons from OrcaSlicer main repo
|
||||||
|
echo "Downloading SVG icons from OrcaSlicer main repo..."
|
||||||
|
grep -roh "https://github.com/OrcaSlicer/OrcaSlicer/blob/main/resources/images/[^?)]*" docs/ 2>/dev/null | \
|
||||||
|
sort -u | while read url; do
|
||||||
|
# Extract filename from URL
|
||||||
|
filename=$(basename "$url")
|
||||||
|
local_path="docs/images/orcaslicer-icons/$filename"
|
||||||
|
|
||||||
|
# Download if not already cached
|
||||||
|
if [ ! -f "$local_path" ]; then
|
||||||
|
# Convert blob URL to raw URL
|
||||||
|
raw_url=$(echo "$url" | sed 's|github.com/OrcaSlicer/OrcaSlicer/blob/main|raw.githubusercontent.com/OrcaSlicer/OrcaSlicer/main|')
|
||||||
|
echo " Downloading: $filename"
|
||||||
|
curl -sL "$raw_url" -o "$local_path" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
else
|
||||||
|
echo "Skipping SVG icon download (use --download-svg or -d to enable)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
find docs -name "*.md" -type f | while read md_file; do
|
||||||
|
# Calculate relative path to images based on file depth
|
||||||
|
depth=$(echo "$md_file" | tr -cd '/' | wc -c)
|
||||||
|
depth=$((depth - 1)) # Subtract 1 for "docs/"
|
||||||
|
|
||||||
|
prefix=""
|
||||||
|
for ((i=0; i<depth; i++)); do
|
||||||
|
prefix="../$prefix"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Replace OrcaSlicer_WIKI GitHub URLs with relative paths
|
||||||
|
sed -i '' "s|https://github.com/OrcaSlicer/OrcaSlicer_WIKI/blob/main/images/\([^?]*\)?raw=true|${prefix}images/\1|g" "$md_file" 2>/dev/null || \
|
||||||
|
sed -i "s|https://github.com/OrcaSlicer/OrcaSlicer_WIKI/blob/main/images/\([^?]*\)?raw=true|${prefix}images/\1|g" "$md_file"
|
||||||
|
|
||||||
|
# Replace OrcaSlicer main repo icon URLs with local paths
|
||||||
|
sed -i '' "s|https://github.com/OrcaSlicer/OrcaSlicer/blob/main/resources/images/\([^?]*\)?raw=true|${prefix}images/orcaslicer-icons/\1|g" "$md_file" 2>/dev/null || \
|
||||||
|
sed -i "s|https://github.com/OrcaSlicer/OrcaSlicer/blob/main/resources/images/\([^?]*\)?raw=true|${prefix}images/orcaslicer-icons/\1|g" "$md_file"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Build mkdocs and output to wiki folder
|
||||||
|
mkdocs build --site-dir wiki
|
||||||
|
|
||||||
|
# Create redirect directories for GitHub wiki-style URLs (e.g., /wiki/quality_settings_layer_height)
|
||||||
|
echo "Creating redirect directories for wiki-style URLs..."
|
||||||
|
create_redirects() {
|
||||||
|
# Find all HTML files (except index.html) and create root-level redirects
|
||||||
|
find wiki -name "*.html" -type f ! -name "index.html" | while read html_file; do
|
||||||
|
# Get the relative path from wiki/
|
||||||
|
rel_path="${html_file#wiki/}"
|
||||||
|
|
||||||
|
# Extract the filename without .html extension
|
||||||
|
filename=$(basename "$rel_path" .html)
|
||||||
|
|
||||||
|
# Skip files already at root level
|
||||||
|
dir_of_file=$(dirname "$rel_path")
|
||||||
|
if [ "$dir_of_file" = "." ]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create redirect directory at root level (for clean URLs without .html)
|
||||||
|
redirect_dir="wiki/${filename}"
|
||||||
|
|
||||||
|
# Skip if directory already exists (could be a real content directory)
|
||||||
|
if [ -d "$redirect_dir" ]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "$redirect_dir"
|
||||||
|
redirect_file="${redirect_dir}/index.html"
|
||||||
|
|
||||||
|
# Calculate relative path from redirect directory to target
|
||||||
|
# Redirect is at wiki/filename/, target is at wiki/rel_path
|
||||||
|
# So we need to go up one level (../) then to rel_path
|
||||||
|
relative_url="../${rel_path}"
|
||||||
|
|
||||||
|
# URL encode spaces in the path
|
||||||
|
encoded_url=$(python3 -c "import urllib.parse, sys; print(urllib.parse.quote(sys.argv[1]))" "${relative_url}" 2>/dev/null || echo "${relative_url}" | sed 's/ /%20/g')
|
||||||
|
|
||||||
|
# Create redirect HTML content
|
||||||
|
cat > "$redirect_file" <<EOF
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="refresh" content="0; url=${encoded_url}">
|
||||||
|
<link rel="canonical" href="${encoded_url}">
|
||||||
|
<script>window.location.replace("${encoded_url}");</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<p>Redirecting to <a href="${encoded_url}">${filename}</a>...</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
EOF
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
create_redirects
|
||||||
|
|
||||||
|
# Clean up docs directory after build
|
||||||
|
rm -rf docs
|
||||||
|
|
||||||
|
echo "Build complete! HTML files are in the wiki/ folder."
|
||||||
310
generate_nav.py
Normal file
310
generate_nav.py
Normal file
@@ -0,0 +1,310 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Auto-generate mkdocs.yml navigation from folder structure.
|
||||||
|
Fully dynamic - scans all folders and markdown files automatically.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
python3 generate_nav.py # Preview nav structure
|
||||||
|
python3 generate_nav.py --update # Update mkdocs.yml directly
|
||||||
|
"""
|
||||||
|
|
||||||
|
import re
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
|
||||||
|
# Folders to exclude from navigation (not documentation content)
|
||||||
|
EXCLUDED_FOLDERS = {
|
||||||
|
'images', 'docs', 'wiki', 'html', 'custom_theme',
|
||||||
|
'.git', '.github', '__pycache__', 'node_modules',
|
||||||
|
'venv', '.venv', 'infill-analysis', 'assets', 'static',
|
||||||
|
}
|
||||||
|
|
||||||
|
# Optional: Override display names for specific folders
|
||||||
|
# If not specified, names are auto-generated from folder names
|
||||||
|
# Format: "folder_name": "Display Name"
|
||||||
|
DISPLAY_NAME_OVERRIDES = {
|
||||||
|
# Examples:
|
||||||
|
# "print_settings": "Process Settings",
|
||||||
|
# "developer-reference": "Developer Section",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def folder_to_title(name: str) -> str:
|
||||||
|
"""Convert a folder name to a readable title."""
|
||||||
|
# Replace separators with spaces
|
||||||
|
title = name.replace('_', ' ').replace('-', ' ')
|
||||||
|
|
||||||
|
# Title case, preserving certain patterns
|
||||||
|
words = title.split()
|
||||||
|
result = []
|
||||||
|
for word in words:
|
||||||
|
lower = word.lower()
|
||||||
|
if lower == 'gcode':
|
||||||
|
result.append('G-Code')
|
||||||
|
elif lower in ['api', 'stl', 'vfa', 'xy', 'semm']:
|
||||||
|
result.append(word.upper())
|
||||||
|
elif lower in ['and', 'or', 'the', 'in', 'on', 'at', 'to', 'for', 'of']:
|
||||||
|
result.append(lower if result else word.title())
|
||||||
|
else:
|
||||||
|
result.append(word.title())
|
||||||
|
return ' '.join(result)
|
||||||
|
|
||||||
|
|
||||||
|
def get_display_name(folder_name: str) -> str:
|
||||||
|
"""Get display name for a folder."""
|
||||||
|
if folder_name in DISPLAY_NAME_OVERRIDES:
|
||||||
|
return DISPLAY_NAME_OVERRIDES[folder_name]
|
||||||
|
return folder_to_title(folder_name)
|
||||||
|
|
||||||
|
|
||||||
|
def extract_title_from_md(filepath: Path) -> Optional[str]:
|
||||||
|
"""Extract the first H1 heading from a markdown file."""
|
||||||
|
try:
|
||||||
|
content = filepath.read_text(encoding='utf-8')
|
||||||
|
match = re.search(r'^#\s+(.+)$', content, re.MULTILINE)
|
||||||
|
if match:
|
||||||
|
return match.group(1).strip()
|
||||||
|
except (UnicodeDecodeError, IOError, PermissionError):
|
||||||
|
# Silently skip files that can't be read
|
||||||
|
pass
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def filename_to_title(filename: str) -> str:
|
||||||
|
"""Convert a filename to a readable title."""
|
||||||
|
name = filename
|
||||||
|
|
||||||
|
# Remove common prefixes (settings files often have category prefixes)
|
||||||
|
# This regex removes patterns like "printer_basic_information_", "quality_settings_", etc.
|
||||||
|
name = re.sub(r'^[a-z]+_(?:[a-z]+_)*(?=\w)', '', name)
|
||||||
|
|
||||||
|
return folder_to_title(name)
|
||||||
|
|
||||||
|
|
||||||
|
def get_file_title(filepath: Path) -> str:
|
||||||
|
"""Get the display title for a markdown file."""
|
||||||
|
# Try to extract from file content first (most accurate)
|
||||||
|
extracted = extract_title_from_md(filepath)
|
||||||
|
if extracted:
|
||||||
|
return extracted
|
||||||
|
# Fall back to filename
|
||||||
|
return filename_to_title(filepath.stem)
|
||||||
|
|
||||||
|
|
||||||
|
def get_sort_key(path: Path) -> tuple:
|
||||||
|
"""Generate a sort key for ordering files/folders."""
|
||||||
|
name = path.name.lower() if path.is_dir() else path.stem.lower()
|
||||||
|
|
||||||
|
# Priority ordering: basic/intro first, advanced/misc last
|
||||||
|
if any(x in name for x in ['index', 'home', 'intro', 'overview', 'guide']):
|
||||||
|
return (0, name)
|
||||||
|
if 'basic' in name:
|
||||||
|
return (1, name)
|
||||||
|
if 'advanced' in name:
|
||||||
|
return (8, name)
|
||||||
|
if any(x in name for x in ['other', 'misc', 'dependencies']):
|
||||||
|
return (9, name)
|
||||||
|
|
||||||
|
return (5, name) # Default: middle priority, alphabetical
|
||||||
|
|
||||||
|
|
||||||
|
def scan_folder(folder: Path, base_path: Path) -> list:
|
||||||
|
"""Recursively scan a folder and build nav structure."""
|
||||||
|
nav_items = []
|
||||||
|
|
||||||
|
try:
|
||||||
|
items = list(folder.iterdir())
|
||||||
|
except PermissionError:
|
||||||
|
return nav_items
|
||||||
|
|
||||||
|
# Separate and sort files and folders
|
||||||
|
md_files = sorted(
|
||||||
|
[f for f in items if f.is_file() and f.suffix == '.md'],
|
||||||
|
key=get_sort_key
|
||||||
|
)
|
||||||
|
subfolders = sorted(
|
||||||
|
[d for d in items if d.is_dir()
|
||||||
|
and not d.name.startswith('.')
|
||||||
|
and d.name.lower() not in EXCLUDED_FOLDERS],
|
||||||
|
key=get_sort_key
|
||||||
|
)
|
||||||
|
|
||||||
|
# Process markdown files
|
||||||
|
for md_file in md_files:
|
||||||
|
title = get_file_title(md_file)
|
||||||
|
rel_path = md_file.relative_to(base_path)
|
||||||
|
nav_items.append((title, str(rel_path)))
|
||||||
|
|
||||||
|
# Process subfolders recursively
|
||||||
|
for subfolder in subfolders:
|
||||||
|
sub_items = scan_folder(subfolder, base_path)
|
||||||
|
if sub_items:
|
||||||
|
folder_title = get_display_name(subfolder.name)
|
||||||
|
nav_items.append((folder_title, sub_items))
|
||||||
|
|
||||||
|
return nav_items
|
||||||
|
|
||||||
|
|
||||||
|
def generate_nav(base_path: Path) -> list:
|
||||||
|
"""Generate the complete navigation structure by scanning all folders."""
|
||||||
|
nav = []
|
||||||
|
|
||||||
|
# Check for Home.md -> becomes index.md
|
||||||
|
if (base_path / 'Home.md').exists():
|
||||||
|
nav.append(("Home", "index.md"))
|
||||||
|
|
||||||
|
# Scan all top-level folders that contain markdown files
|
||||||
|
top_level_folders = sorted(
|
||||||
|
[d for d in base_path.iterdir()
|
||||||
|
if d.is_dir()
|
||||||
|
and not d.name.startswith('.')
|
||||||
|
and d.name.lower() not in EXCLUDED_FOLDERS
|
||||||
|
and any(d.rglob('*.md'))], # Only include if has .md files
|
||||||
|
key=get_sort_key
|
||||||
|
)
|
||||||
|
|
||||||
|
# Build nav from each folder
|
||||||
|
for folder in top_level_folders:
|
||||||
|
items = scan_folder(folder, base_path)
|
||||||
|
if items:
|
||||||
|
section_title = get_display_name(folder.name)
|
||||||
|
nav.append((section_title, items))
|
||||||
|
|
||||||
|
return nav
|
||||||
|
|
||||||
|
|
||||||
|
def escape_yaml_string(s: str) -> str:
|
||||||
|
"""Escape special YAML characters in a string."""
|
||||||
|
# Characters that need quoting in YAML
|
||||||
|
special_chars = set(':{}[],&*#?|-<>=!%@\\')
|
||||||
|
if any(c in s for c in special_chars) or ' ' in s or s.startswith('"') or s.startswith("'"):
|
||||||
|
# Escape quotes and backslashes, then wrap in double quotes
|
||||||
|
escaped = s.replace('\\', '\\\\').replace('"', '\\"')
|
||||||
|
return f'"{escaped}"'
|
||||||
|
return s
|
||||||
|
|
||||||
|
|
||||||
|
def nav_to_yaml(nav: list, indent: int = 2) -> str:
|
||||||
|
"""Convert nav structure to YAML string."""
|
||||||
|
lines = []
|
||||||
|
base_indent = " " * indent
|
||||||
|
|
||||||
|
def format_item(item, level):
|
||||||
|
prefix = base_indent * level + "- "
|
||||||
|
title, value = item
|
||||||
|
|
||||||
|
# Escape title to handle special characters
|
||||||
|
escaped_title = escape_yaml_string(title)
|
||||||
|
|
||||||
|
if isinstance(value, list):
|
||||||
|
lines.append(f"{prefix}{escaped_title}:")
|
||||||
|
for sub_item in value:
|
||||||
|
format_item(sub_item, level + 1)
|
||||||
|
else:
|
||||||
|
# Escape path value
|
||||||
|
escaped_value = escape_yaml_string(value)
|
||||||
|
lines.append(f"{prefix}{escaped_title}: {escaped_value}")
|
||||||
|
|
||||||
|
for item in nav:
|
||||||
|
format_item(item, 0)
|
||||||
|
|
||||||
|
return '\n'.join(lines)
|
||||||
|
|
||||||
|
|
||||||
|
def update_mkdocs_yml(mkdocs_path: Path, nav_yaml: str) -> None:
|
||||||
|
"""Update the nav section in mkdocs.yml."""
|
||||||
|
content = mkdocs_path.read_text(encoding='utf-8')
|
||||||
|
|
||||||
|
# Find and replace the nav section
|
||||||
|
# Match nav: followed by indented content until next top-level key or EOF
|
||||||
|
nav_pattern = re.compile(
|
||||||
|
r'^nav:\s*\n((?:[ \t]+.*\n)*?)(?=^[a-zA-Z]|\Z)',
|
||||||
|
re.MULTILINE | re.DOTALL
|
||||||
|
)
|
||||||
|
|
||||||
|
match = nav_pattern.search(content)
|
||||||
|
if match:
|
||||||
|
new_content = content[:match.start()] + f"nav:\n{nav_yaml}\n" + content[match.end():]
|
||||||
|
else:
|
||||||
|
new_content = content.rstrip() + f"\n\nnav:\n{nav_yaml}\n"
|
||||||
|
|
||||||
|
# Validate YAML before writing (basic check - try importing yaml if available)
|
||||||
|
try:
|
||||||
|
import yaml
|
||||||
|
yaml.safe_load(new_content)
|
||||||
|
except ImportError:
|
||||||
|
# yaml module not available, skip validation
|
||||||
|
pass
|
||||||
|
except yaml.YAMLError as e:
|
||||||
|
raise ValueError(f"Generated YAML is invalid: {e}") from e
|
||||||
|
|
||||||
|
mkdocs_path.write_text(new_content, encoding='utf-8')
|
||||||
|
print(f"✅ Updated {mkdocs_path}")
|
||||||
|
|
||||||
|
|
||||||
|
def print_nav_tree(nav: list, indent: int = 0) -> None:
|
||||||
|
"""Pretty print the navigation structure."""
|
||||||
|
for title, value in nav:
|
||||||
|
prefix = " " * indent
|
||||||
|
if isinstance(value, list):
|
||||||
|
print(f"{prefix}📁 {title}")
|
||||||
|
print_nav_tree(value, indent + 1)
|
||||||
|
else:
|
||||||
|
print(f"{prefix}📄 {title}")
|
||||||
|
|
||||||
|
|
||||||
|
def count_items(nav: list) -> int:
|
||||||
|
"""Count total navigation items."""
|
||||||
|
count = 0
|
||||||
|
for _, value in nav:
|
||||||
|
if isinstance(value, list):
|
||||||
|
count += count_items(value)
|
||||||
|
else:
|
||||||
|
count += 1
|
||||||
|
return count
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description='Generate mkdocs.yml navigation from folder structure (fully dynamic)'
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--update', '-u', action='store_true',
|
||||||
|
help='Update mkdocs.yml directly (default: preview only)'
|
||||||
|
)
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
script_dir = Path(__file__).parent
|
||||||
|
mkdocs_path = script_dir / 'mkdocs.yml'
|
||||||
|
|
||||||
|
if not mkdocs_path.exists():
|
||||||
|
print(f"❌ Error: {mkdocs_path} not found")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
print(f"📂 Scanning: {script_dir}\n")
|
||||||
|
nav = generate_nav(script_dir)
|
||||||
|
nav_yaml = nav_to_yaml(nav)
|
||||||
|
|
||||||
|
print("📋 Navigation Structure:\n")
|
||||||
|
print_nav_tree(nav)
|
||||||
|
print(f"\n📊 Total pages: {count_items(nav)}")
|
||||||
|
print(f"📁 Total sections: {len(nav) - 1}") # -1 for Home
|
||||||
|
|
||||||
|
if args.update:
|
||||||
|
print()
|
||||||
|
update_mkdocs_yml(mkdocs_path, nav_yaml)
|
||||||
|
else:
|
||||||
|
print("\n" + "=" * 60)
|
||||||
|
print("Generated YAML (use --update to apply):\n")
|
||||||
|
print("nav:")
|
||||||
|
print(nav_yaml)
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
exit(main())
|
||||||
140
mkdocs.yml
Normal file
140
mkdocs.yml
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
site_name: OrcaSlicer WIKI
|
||||||
|
site_description: Official Wiki for OrcaSlicer - A powerful open source slicer for FFF (FDM) 3D Printers
|
||||||
|
site_url: https://www.orcaslicer.com/wiki
|
||||||
|
|
||||||
|
# MkDocs requires docs_dir to be a subdirectory
|
||||||
|
# The build script will handle the file structure
|
||||||
|
docs_dir: docs
|
||||||
|
site_dir: html
|
||||||
|
|
||||||
|
# Use flat URLs (page.html) instead of directory URLs (page/index.html)
|
||||||
|
use_directory_urls: false
|
||||||
|
|
||||||
|
# Theme configuration
|
||||||
|
theme:
|
||||||
|
name: readthedocs
|
||||||
|
|
||||||
|
# Markdown extensions (using built-in extensions to avoid extra dependencies)
|
||||||
|
markdown_extensions:
|
||||||
|
- codehilite:
|
||||||
|
guess_lang: false
|
||||||
|
- fenced_code
|
||||||
|
- tables
|
||||||
|
- toc:
|
||||||
|
permalink: true
|
||||||
|
- attr_list
|
||||||
|
- md_in_html
|
||||||
|
|
||||||
|
# Navigation structure based on Home.md
|
||||||
|
nav:
|
||||||
|
- Home: index.md
|
||||||
|
- Calibration:
|
||||||
|
- "Adaptive Pressure Advance": "calibration/adaptive-pressure-advance-calib.md"
|
||||||
|
- "Calibration Guide": calibration/Calibration.md
|
||||||
|
- Cornering: "calibration/cornering-calib.md"
|
||||||
|
- "Flow Rate Calibration": "calibration/flow-rate-calib.md"
|
||||||
|
- "Input Shaping": "calibration/input-shaping-calib.md"
|
||||||
|
- "Pressure Advance": "calibration/pressure-advance-calib.md"
|
||||||
|
- "Retraction test": "calibration/retraction-calib.md"
|
||||||
|
- "Temp Calibration": "calibration/temp-calib.md"
|
||||||
|
- "Filament Tolerance Calibration": "calibration/tolerance-calib.md"
|
||||||
|
- VFA: "calibration/vfa-calib.md"
|
||||||
|
- "Max Volumetric Speed (FlowRate) Calibration": "calibration/volumetric-speed-calib.md"
|
||||||
|
- "Developer Reference":
|
||||||
|
- "Localization and translation guide": "developer-reference/Localization_guide.md"
|
||||||
|
- "Placeholders Variables": "developer-reference/Built-in-placeholders-variables.md"
|
||||||
|
- "How to Build": "developer-reference/How-to-build.md"
|
||||||
|
- "Guide: Develop Profiles for OrcaSlicer": "developer-reference/How-to-create-profiles.md"
|
||||||
|
- "How to Test": "developer-reference/How-to-test.md"
|
||||||
|
- "How to Contribute to the Wiki": "developer-reference/How-to-wiki.md"
|
||||||
|
- "Application Structure Overview": "developer-reference/plater-sidebar-tab-combobox.md"
|
||||||
|
- "Preset and Bundle": "developer-reference/Preset-and-bundle.md"
|
||||||
|
- "Slicing Hierarchy": "developer-reference/slicing-hierarchy.md"
|
||||||
|
- "General Settings":
|
||||||
|
- "Keyboard Shortcuts": "general-settings/keyboard-shortcuts.md"
|
||||||
|
- "Material Settings":
|
||||||
|
- Cooling:
|
||||||
|
- "Material Cooling": material_settings/cooling/material_cooling.md
|
||||||
|
- Filament:
|
||||||
|
- "Material Basic Information": material_settings/filament/material_basic_information.md
|
||||||
|
- "Material Flow Ratio and Pressure Advance": material_settings/filament/material_flow_ratio_and_pressure_advance.md
|
||||||
|
- "Material Temperatures": material_settings/filament/material_temperatures.md
|
||||||
|
- "Material Volumetric Speed Limitation": material_settings/filament/material_volumetric_speed_limitation.md
|
||||||
|
- Multimaterial:
|
||||||
|
- "Material Multimaterial Settings": material_settings/multimaterial/material_multimaterial.md
|
||||||
|
- "Setting Overrides":
|
||||||
|
- "Material Setting Overrides": "material_settings/setting overrides/material_setting_overrides.md"
|
||||||
|
- Advanced:
|
||||||
|
- "Advanced Material Settings": material_settings/advanced/material_advanced.md
|
||||||
|
- Dependencies:
|
||||||
|
- "Material Dependencies": material_settings/dependencies/material_dependencies.md
|
||||||
|
- "Print Prepare":
|
||||||
|
- "STL Transformation": "print_prepare/stl-transformation.md"
|
||||||
|
- "Print Settings":
|
||||||
|
- Multimaterial:
|
||||||
|
- "Filament for Features": print_settings/multimaterial/multimaterial_settings_filament_for_features.md
|
||||||
|
- "Flush Options": print_settings/multimaterial/multimaterial_settings_flush_options.md
|
||||||
|
- "Ooze prevention": print_settings/multimaterial/multimaterial_settings_ooze_prevention.md
|
||||||
|
- "Prime Tower": print_settings/multimaterial/multimaterial_settings_prime_tower.md
|
||||||
|
- "Multimaterial Advanced": print_settings/multimaterial/multimaterial_settings_advanced.md
|
||||||
|
- Quality:
|
||||||
|
- Bridging: print_settings/quality/quality_settings_bridging.md
|
||||||
|
- Ironing: print_settings/quality/quality_settings_ironing.md
|
||||||
|
- "Layer Height": print_settings/quality/quality_settings_layer_height.md
|
||||||
|
- "Line Width": print_settings/quality/quality_settings_line_width.md
|
||||||
|
- Overhangs: print_settings/quality/quality_settings_overhangs.md
|
||||||
|
- Precision: print_settings/quality/quality_settings_precision.md
|
||||||
|
- Seam: print_settings/quality/quality_settings_seam.md
|
||||||
|
- "Wall and surfaces": print_settings/quality/quality_settings_wall_and_surfaces.md
|
||||||
|
- "Wall Generator": print_settings/quality/quality_settings_wall_generator.md
|
||||||
|
- Speed:
|
||||||
|
- Acceleration: print_settings/speed/speed_settings_acceleration.md
|
||||||
|
- "Initial layer speed": print_settings/speed/speed_settings_initial_layer_speed.md
|
||||||
|
- "Jerk XY": print_settings/speed/speed_settings_jerk_xy.md
|
||||||
|
- "Overhang Speed": print_settings/speed/speed_settings_overhang_speed.md
|
||||||
|
- Travel: print_settings/speed/speed_settings_travel.md
|
||||||
|
- "Speed Advanced - Extrusion Rate Smoothing": print_settings/speed/speed_settings_advanced.md
|
||||||
|
- "Other layers speed": print_settings/speed/speed_settings_other_layers_speed.md
|
||||||
|
- Strength:
|
||||||
|
- Infill: print_settings/strength/strength_settings_infill.md
|
||||||
|
- "Infill rotation template metalanguage": print_settings/strength/strength_settings_infill_rotation_template_metalanguage.md
|
||||||
|
- Patterns: print_settings/strength/strength_settings_patterns.md
|
||||||
|
- "Top and Bottom Shells": print_settings/strength/strength_settings_top_bottom_shells.md
|
||||||
|
- Walls: print_settings/strength/strength_settings_walls.md
|
||||||
|
- "Strength Advanced": print_settings/strength/strength_settings_advanced.md
|
||||||
|
- Support:
|
||||||
|
- "Support Filament": print_settings/support/support_settings_filament.md
|
||||||
|
- "Support Ironing": print_settings/support/support_settings_ironing.md
|
||||||
|
- Raft: print_settings/support/support_settings_raft.md
|
||||||
|
- Support: print_settings/support/support_settings_support.md
|
||||||
|
- "Tree Support": print_settings/support/support_settings_tree.md
|
||||||
|
- "Support Advanced": print_settings/support/support_settings_advanced.md
|
||||||
|
- Others:
|
||||||
|
- Brim: print_settings/others/others_settings_brim.md
|
||||||
|
- "Fuzzy Skin": print_settings/others/others_settings_fuzzy_skin.md
|
||||||
|
- "G-Code Output": print_settings/others/others_settings_g_code_output.md
|
||||||
|
- Notes: print_settings/others/others_settings_notes.md
|
||||||
|
- "Post-Processing Scripts": print_settings/others/others_settings_post_processing_scripts.md
|
||||||
|
- Skirt: print_settings/others/others_settings_skirt.md
|
||||||
|
- "Special Mode": print_settings/others/others_settings_special_mode.md
|
||||||
|
- "Printer Settings":
|
||||||
|
- "Basic Information":
|
||||||
|
- "Printer Accessory": "printer_settings/basic information/printer_basic_information_accessory.md"
|
||||||
|
- "Adaptive Bed Mesh": "printer_settings/basic information/printer_basic_information_adaptive_bed_mesh.md"
|
||||||
|
- "Advanced Printer Settings": "printer_settings/basic information/printer_basic_information_advanced.md"
|
||||||
|
- "Cooling Fan": "printer_settings/basic information/printer_basic_information_cooling_fan.md"
|
||||||
|
- "Extruder Clearance": "printer_settings/basic information/printer_basic_information_extruder_clearance.md"
|
||||||
|
- "Printable Space": "printer_settings/basic information/printer_basic_information_printable_space.md"
|
||||||
|
- Extruder:
|
||||||
|
- "Basic Extruder Information": printer_settings/extruder/printer_extruder_basic_information.md
|
||||||
|
- Retraction: printer_settings/extruder/printer_extruder_retraction.md
|
||||||
|
- "Z Hop": printer_settings/extruder/printer_extruder_z_hop.md
|
||||||
|
- "Machine G-Code":
|
||||||
|
- "Machine G-code": "printer_settings/machine gcode/printer_machine_gcode.md"
|
||||||
|
- "Motion Ability":
|
||||||
|
- "Motion Ability": "printer_settings/motion ability/printer_motion_ability.md"
|
||||||
|
- Multimaterial:
|
||||||
|
- "Single Extruder Multi-Material Parameters": printer_settings/multimaterial/printer_multimaterial_semm_parameters.md
|
||||||
|
- "Multimaterial setup": printer_settings/multimaterial/printer_multimaterial_setup.md
|
||||||
|
- "Wipe Tower": printer_settings/multimaterial/printer_multimaterial_wipe_tower.md
|
||||||
|
- "Advanced Multi-Material Settings": printer_settings/multimaterial/printer_multimaterial_advanced.md
|
||||||
Reference in New Issue
Block a user