diff --git a/.github/workflows/deploy_docs_ghpage.yml b/.github/workflows/deploy_docs_ghpage.yml index 5e241a4bf..2dabcda8c 100644 --- a/.github/workflows/deploy_docs_ghpage.yml +++ b/.github/workflows/deploy_docs_ghpage.yml @@ -13,6 +13,10 @@ jobs: env: WIKI_SUBFOLDER: Developer-Wiki steps: + - uses: actions/setup-python@v5 + with: + python-version: "3.11" + - uses: ts-graphviz/setup-graphviz@v1 - name: Checkout Main Repository uses: actions/checkout@v5 @@ -25,6 +29,10 @@ jobs: # Create temporary wiki subfolder path: docs/${{ env.WIKI_SUBFOLDER }} + - name: Install daqpytools for uml generation + run : | + pip install "daqpytools[dev] @ git+https://github.com/DUNE-DAQ/daqpytools.git@develop" + # Move Archives to a temp folder so they aren't processed - name: Hide Archive files from script run: | @@ -43,6 +51,14 @@ jobs: python docs/utils/process_wiki.py $GITHUB_PAGES_BASE $WIKI_SUBFOLDER cd ~ + - name: run uml generation + env: + PYTHONPATH: ${{ github.workspace }}/src + run: | + daqpytools-generate-uml drunc --directory . --output-directory pics --split + mkdir docs/class_diagrams + mv pics/split/classes_styled/*.png docs/class_diagrams + - name: Install dependencies run: | python -m pip install --upgrade pip diff --git a/docs/__init__.py b/docs/__init__.py new file mode 100644 index 000000000..fcfdefbdf --- /dev/null +++ b/docs/__init__.py @@ -0,0 +1 @@ +"""Docs package used for MkDocs macros.""" diff --git a/docs/gallery.md b/docs/gallery.md new file mode 100644 index 000000000..f8a04624e --- /dev/null +++ b/docs/gallery.md @@ -0,0 +1,3 @@ +# Image Gallery + +{{ image_folder("class_diagrams", cols=4) }} diff --git a/docs/gallery_generator.py b/docs/gallery_generator.py new file mode 100644 index 000000000..dd8a7e2c4 --- /dev/null +++ b/docs/gallery_generator.py @@ -0,0 +1,92 @@ +""" +Macro generator for image galleries in MkDocs. + +This module provides a macro that automatically renders all images from a folder +as a responsive grid. It's used by mkdocs-macros-plugin. + +Usage in markdown: + {{ image_folder("img", cols=4) }} + {{ image_folder("assets/diagrams", cols=3) }} +""" + +import html +from pathlib import Path + +IMAGE_EXTS = {".png", ".jpg", ".jpeg", ".gif", ".webp", ".svg"} + + +def define_env(env): + """ + Define the image_folder macro for mkdocs-macros-plugin. + + Args: + env: The mkdocs-macros environment object. + """ + + @env.macro + def image_folder(folder, cols=4): + """ + Render a responsive image grid for a folder under docs/. + + Automatically enumerates all image files in the folder and renders them + as a grid with captions from filenames. New images are picked up automatically + on rebuild without requiring markdown changes. + + Usage: + {{ image_folder("img") }} # 4-column grid + {{ image_folder("assets/diagrams", cols=3) }} # 3-column grid + + Args: + folder: Path relative to docs/ (e.g., "img" or "assets/generated-images") + cols: Number of columns in the grid (default: 4) + + Returns: + HTML string with grid of images, or error message if folder not found. + """ + source_docs_dir = Path(__file__).resolve().parent + target_dir = (source_docs_dir / folder).resolve() + + # Safety check: ensure folder is inside the source docs tree. + if source_docs_dir not in target_dir.parents and target_dir != source_docs_dir: + return f"

Error: Image folder path is outside docs/: {html.escape(folder)}

" + + if not target_dir.exists() or not target_dir.is_dir(): + return ( + f"

Image folder not found: {html.escape(folder)}

" + ) + + # Collect all image files, sorted by name + files = sorted( + [ + p + for p in target_dir.iterdir() + if p.is_file() and p.suffix.lower() in IMAGE_EXTS + ], + key=lambda p: p.name.lower(), + ) + + if not files: + return f"

No images found in {html.escape(folder)}

" + + # Render HTML grid + col_style = f"repeat({int(cols)}, minmax(0, 1fr))" + out = [ + f'
' + ] + + for p in files: + rel = f"{folder.rstrip('/')}/{p.name}" + page_rel = f"../{rel}" + caption = p.stem # filename without extension + + out.append( + "
" + f'' + f'{html.escape(caption)}' + "" + f"
{html.escape(caption)}
" + "
" + ) + + out.append("
") + return "\n".join(out) diff --git a/docs/requirements.txt b/docs/requirements.txt index 4cecee11b..87b827d7d 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -7,4 +7,5 @@ mkdocs-section-index mkdocstrings mkdocstrings-python pymdown-extensions -mkdocs-exclude \ No newline at end of file +mkdocs-exclude +mkdocs-macros-plugin \ No newline at end of file diff --git a/docs/stylesheets/gallery.css b/docs/stylesheets/gallery.css new file mode 100644 index 000000000..c15274f33 --- /dev/null +++ b/docs/stylesheets/gallery.css @@ -0,0 +1,23 @@ +.image-folder-grid { + display: grid; + gap: 12px; + align-items: start; +} + +.image-folder-grid figure { + margin: 0; +} + +.image-folder-grid img { + width: 100%; + height: auto; + display: block; + border-radius: 6px; +} + +.image-folder-grid figcaption { + font-size: 0.75rem; + opacity: 0.8; + margin-top: 6px; + word-break: break-word; +} diff --git a/mkdocs.yml b/mkdocs.yml index 605806279..829ed675b 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -34,6 +34,8 @@ plugins: - exclude: glob: - Developer-Wiki/* + - macros: + module_name: docs/gallery_generator - gen-files: scripts: - docs/utils/generate_ghpages_docstrings.py @@ -51,5 +53,8 @@ plugins: merge_init_into_class: true paths: [.] +extra_css: + - stylesheets/gallery.css + hooks: - docs/utils/mkdocs_hooks.py \ No newline at end of file