mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2025-04-28 10:26:54 +02:00
Compare commits
12 Commits
f21120e9f7
...
8d8016a01e
Author | SHA1 | Date | |
---|---|---|---|
8d8016a01e | |||
d390b500b4 | |||
be62b72e90 | |||
af27d50214 | |||
e6fa74df61 | |||
4cde1ed9e4 | |||
858b906722 | |||
3a32b65454 | |||
12df136ccf | |||
71cde6bf3f | |||
9dfd019e0a | |||
756407d407 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -2,3 +2,4 @@ site.retry
|
|||||||
*__pycache__
|
*__pycache__
|
||||||
docs/*
|
docs/*
|
||||||
venv
|
venv
|
||||||
|
*.log
|
10
Makefile
10
Makefile
@ -1,12 +1,12 @@
|
|||||||
.PHONY: install deinstall refresh
|
.PHONY: install deinstall refresh
|
||||||
|
|
||||||
install:
|
install:
|
||||||
$(MAKE) -C sphinx html
|
$(MAKE) -C sphinx html $(MAKEFLAGS)
|
||||||
$(MAKE) -C sphinx install
|
$(MAKE) -C sphinx install $(MAKEFLAGS)
|
||||||
|
|
||||||
deinstall:
|
deinstall:
|
||||||
$(MAKE) -C sphinx clean
|
$(MAKE) -C sphinx clean $(MAKEFLAGS)
|
||||||
|
|
||||||
refresh:
|
refresh:
|
||||||
$(MAKE) -C sphinx clean
|
$(MAKE) -C sphinx clean $(MAKEFLAGS)
|
||||||
$(MAKE) -C sphinx html
|
$(MAKE) -C sphinx html $(MAKEFLAGS)
|
||||||
|
@ -22,4 +22,9 @@ This command cleans the previous build and generates the updated documentation.
|
|||||||
|
|
||||||
#### On Server
|
#### On Server
|
||||||
|
|
||||||
In your inventory file, enable the **Sphinx** role. When activated, the documentation will be automatically generated and deployed under the **docs** subdomain of your CyMaIS instance. This ensures your documentation is always current and easily accessible 🔄🌐.
|
|
||||||
|
### Debug
|
||||||
|
To debug and produce an .log execute:
|
||||||
|
```bash
|
||||||
|
pkgmgr shell cymais -c "make refresh SPHINXOPTS='-v -c .' 2>&1 | tee debug.log"
|
||||||
|
```
|
BIN
sphinx/_static/img/logo_cymais.png
Normal file
BIN
sphinx/_static/img/logo_cymais.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 286 KiB |
102
sphinx/_static/js/current-nav.js
Normal file
102
sphinx/_static/js/current-nav.js
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
|
// Initialization: wait for window load and then trigger current nav detection.
|
||||||
|
window.addEventListener("load", function() {
|
||||||
|
console.log("Window loaded, initializing current nav...");
|
||||||
|
initCurrentNav();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Re-trigger when the hash changes.
|
||||||
|
window.addEventListener("hashchange", function() {
|
||||||
|
console.log("Hash changed, reinitializing current nav...");
|
||||||
|
initCurrentNav();
|
||||||
|
});
|
||||||
|
|
||||||
|
function initCurrentNav() {
|
||||||
|
// If Alpine.js is available and provides nextTick, use it.
|
||||||
|
if (window.Alpine && typeof window.Alpine.nextTick === 'function') {
|
||||||
|
window.Alpine.nextTick(processNav);
|
||||||
|
} else {
|
||||||
|
processNav();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function processNav() {
|
||||||
|
var currentHash = window.location.hash;
|
||||||
|
console.log("initCurrentNav: Current hash:", currentHash);
|
||||||
|
if (!currentHash) return;
|
||||||
|
|
||||||
|
// Select all internal links within the .current-index container.
|
||||||
|
var links = document.querySelectorAll('.current-index a.reference.internal');
|
||||||
|
links.forEach(function(link) {
|
||||||
|
var href = link.getAttribute("href");
|
||||||
|
console.log("initCurrentNav: Checking link:", href);
|
||||||
|
// If the link is hash-only (e.g. "#setup-guide")
|
||||||
|
if (href && href.trim().startsWith("#")) {
|
||||||
|
if (href.trim() === currentHash.trim()) {
|
||||||
|
console.log("initCurrentNav: Match found for hash-only link:", href);
|
||||||
|
document.querySelectorAll('.current-index a.reference.internal.current').forEach(function(link) {
|
||||||
|
link.classList.remove("current");
|
||||||
|
});
|
||||||
|
link.classList.add("current");
|
||||||
|
markAsCurrent(link);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Otherwise, if the link includes a file and a hash, compare the hash part.
|
||||||
|
else if (href && href.indexOf('#') !== -1) {
|
||||||
|
var parts = href.split('#');
|
||||||
|
var linkHash = "#" + parts[1].trim();
|
||||||
|
console.log("initCurrentNav: Extracted link hash:", linkHash);
|
||||||
|
if (linkHash === currentHash.trim()) {
|
||||||
|
console.log("initCurrentNav: Match found for link with file and hash:", href);
|
||||||
|
markAsCurrent(link);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
console.log("initCurrentNav: No match for link:", href);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// After processing links, open submenus only for those li elements marked as current.
|
||||||
|
openCurrentSubmenus();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark the link's parent li and all its ancestor li elements as current.
|
||||||
|
function markAsCurrent(link) {
|
||||||
|
var li = link.closest("li");
|
||||||
|
if (!li) {
|
||||||
|
console.log("markAsCurrent: No parent li found for link:", link);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
li.classList.add("current");
|
||||||
|
console.log("markAsCurrent: Marked li as current:", li);
|
||||||
|
// If Alpine.js is used, set its "expanded" property to true.
|
||||||
|
if (li.__x && li.__x.$data) {
|
||||||
|
li.__x.$data.expanded = true;
|
||||||
|
console.log("markAsCurrent: Set Alpine expanded on li:", li);
|
||||||
|
}
|
||||||
|
// Propagate upward: mark all ancestor li elements as current.
|
||||||
|
var parentLi = li.parentElement.closest("li");
|
||||||
|
while (parentLi) {
|
||||||
|
parentLi.classList.add("current");
|
||||||
|
if (parentLi.__x && parentLi.__x.$data) {
|
||||||
|
parentLi.__x.$data.expanded = true;
|
||||||
|
}
|
||||||
|
console.log("markAsCurrent: Propagated current to ancestor li:", parentLi);
|
||||||
|
parentLi = parentLi.parentElement.closest("li");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open immediate submenu elements (the direct children with x-show) of li.current.
|
||||||
|
function openCurrentSubmenus() {
|
||||||
|
document.querySelectorAll('.current-index li.current').forEach(function(li) {
|
||||||
|
// Only target immediate child elements that have x-show.
|
||||||
|
li.querySelectorAll(":scope > [x-show]").forEach(function(elem) {
|
||||||
|
if (elem.style.display === "none" || elem.style.display === "") {
|
||||||
|
elem.style.display = "block";
|
||||||
|
console.log("openCurrentSubmenus: Opened submenu element:", elem);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
window.initCurrentNav = initCurrentNav;
|
||||||
|
});
|
@ -1,12 +1,14 @@
|
|||||||
# Configuration file for the Sphinx documentation builder.
|
|
||||||
#
|
|
||||||
# For the full list of built-in configuration values, see the documentation:
|
|
||||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html
|
|
||||||
|
|
||||||
# -- Project information -----------------------------------------------------
|
|
||||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
|
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
import logging
|
||||||
|
|
||||||
|
# Check if a verbose flag is present in the command line arguments.
|
||||||
|
if any(arg in sys.argv for arg in ["-v", "--verbose"]):
|
||||||
|
logging_level = logging.DEBUG
|
||||||
|
else:
|
||||||
|
logging_level = logging.INFO
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging_level)
|
||||||
|
|
||||||
import os
|
import os
|
||||||
sys.path.insert(0, os.path.abspath('.'))
|
sys.path.insert(0, os.path.abspath('.'))
|
||||||
|
|
||||||
@ -15,33 +17,27 @@ copyright = '2025, Kevin Veen-Birkenbach'
|
|||||||
author = 'Kevin Veen-Birkenbach'
|
author = 'Kevin Veen-Birkenbach'
|
||||||
|
|
||||||
# -- General configuration ---------------------------------------------------
|
# -- General configuration ---------------------------------------------------
|
||||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
|
|
||||||
|
|
||||||
templates_path = ['templates']
|
templates_path = ['templates']
|
||||||
exclude_patterns = ['docs', 'venv', 'venv/**']
|
exclude_patterns = ['docs', 'venv', 'venv/**']
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# -- Options for HTML output -------------------------------------------------
|
# -- Options for HTML output -------------------------------------------------
|
||||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
|
|
||||||
|
|
||||||
html_theme = 'sphinxawesome_theme'
|
html_theme = 'sphinxawesome_theme'
|
||||||
html_static_path = ['static']
|
html_static_path = ['_static']
|
||||||
|
|
||||||
html_sidebars = {
|
html_sidebars = {
|
||||||
'**': [
|
'**': [
|
||||||
#'globaltoc.html',
|
'logo.html',
|
||||||
# 'relations.html',
|
|
||||||
# 'sourcelink.html',
|
|
||||||
'structure.html', # Include your custom template
|
'structure.html', # Include your custom template
|
||||||
# 'searchbox.html',
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cymais_logo = "_static/img/logo_cymais.png"
|
||||||
|
html_favicon = cymais_logo
|
||||||
|
|
||||||
html_theme_options = {
|
html_theme_options = {
|
||||||
# 'fixed_sidebar': True,
|
|
||||||
"show_prev_next": False,
|
"show_prev_next": False,
|
||||||
|
"logo_light": cymais_logo,
|
||||||
|
"logo_dark": cymais_logo,
|
||||||
}
|
}
|
||||||
|
|
||||||
source_suffix = {
|
source_suffix = {
|
||||||
@ -73,6 +69,3 @@ def setup(app):
|
|||||||
if directive is not None:
|
if directive is not None:
|
||||||
directive.optional_arguments = 10
|
directive.optional_arguments = 10
|
||||||
return {'version': '1.0', 'parallel_read_safe': True}
|
return {'version': '1.0', 'parallel_read_safe': True}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,17 +1,27 @@
|
|||||||
import os
|
import os
|
||||||
from sphinx.util import logging
|
import sys
|
||||||
|
import logging as std_logging # Use the standard logging module
|
||||||
|
from sphinx.util import logging # Sphinx logging is used elsewhere if needed
|
||||||
from docutils.parsers.rst import Directive
|
from docutils.parsers.rst import Directive
|
||||||
from .nav_utils import natural_sort_key, extract_headings_from_file, group_headings, sort_tree, MAX_HEADING_LEVEL, DEFAULT_MAX_NAV_DEPTH
|
from .nav_utils import natural_sort_key, extract_headings_from_file, group_headings, sort_tree, MAX_HEADING_LEVEL, DEFAULT_MAX_NAV_DEPTH
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
# Set up our logger based on command-line args.
|
||||||
|
logger = std_logging.getLogger(__name__)
|
||||||
|
if any(arg in sys.argv for arg in ["-v", "--verbose"]):
|
||||||
|
logger.setLevel(std_logging.DEBUG)
|
||||||
|
else:
|
||||||
|
logger.setLevel(std_logging.INFO)
|
||||||
|
|
||||||
DEFAULT_MAX_NAV_DEPTH = 4
|
DEFAULT_MAX_NAV_DEPTH = 4
|
||||||
|
|
||||||
def add_local_file_headings(app, pagename, templatename, context, doctree):
|
def add_local_file_headings(app, pagename, templatename, context, doctree):
|
||||||
|
logger.debug("add_local_file_headings called with pagename: %s", pagename)
|
||||||
|
|
||||||
srcdir = app.srcdir
|
srcdir = app.srcdir
|
||||||
directory = os.path.dirname(pagename)
|
directory = os.path.dirname(pagename)
|
||||||
abs_dir = os.path.join(srcdir, directory)
|
abs_dir = os.path.join(srcdir, directory)
|
||||||
if not os.path.isdir(abs_dir):
|
if not os.path.isdir(abs_dir):
|
||||||
logger.warning(f"Directory {abs_dir} not found for page {pagename}.")
|
logger.warning("Directory %s not found for page %s.", abs_dir, pagename)
|
||||||
context['local_md_headings'] = []
|
context['local_md_headings'] = []
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -41,6 +51,8 @@ def add_local_file_headings(app, pagename, templatename, context, doctree):
|
|||||||
})
|
})
|
||||||
tree = group_headings(file_items)
|
tree = group_headings(file_items)
|
||||||
sort_tree(tree)
|
sort_tree(tree)
|
||||||
|
|
||||||
|
logger.debug("Generated tree: %s", tree)
|
||||||
context['local_md_headings'] = tree
|
context['local_md_headings'] = tree
|
||||||
|
|
||||||
def setup(app):
|
def setup(app):
|
||||||
|
5
sphinx/templates/logo.html
Normal file
5
sphinx/templates/logo.html
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<div class="sidebar-logo" style="text-align: center; margin-bottom: 1em;">
|
||||||
|
<img src="{{ pathto("_static/img/logo_cymais.png", 1) }}" alt="Logo" style="max-width: 100%;">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
@ -9,7 +9,7 @@
|
|||||||
<div class="menu-item" style="display: inline-flex; align-items: center; justify-content: space-between; width: 100%; white-space: nowrap;">
|
<div class="menu-item" style="display: inline-flex; align-items: center; justify-content: space-between; width: 100%; white-space: nowrap;">
|
||||||
<!-- Link and file open section -->
|
<!-- Link and file open section -->
|
||||||
<div style="display: inline-flex; align-items: center; white-space: nowrap;">
|
<div style="display: inline-flex; align-items: center; white-space: nowrap;">
|
||||||
<a class="reference internal{% if item.children %} expandable{% endif %}{% if item.current %} current{% endif %}"
|
<a class="reference internal{% if item.children %} expandable{% endif %}{% if item.current and not item.children %} current{% endif %}"
|
||||||
href="{{ pathto(item.link).replace('#', '') }}{% if item.anchor %}#{{ item.anchor }}{% endif %}"
|
href="{{ pathto(item.link).replace('#', '') }}{% if item.anchor %}#{{ item.anchor }}{% endif %}"
|
||||||
style="text-decoration: none; white-space: nowrap;">
|
style="text-decoration: none; white-space: nowrap;">
|
||||||
{{ item.text }}
|
{{ item.text }}
|
||||||
@ -41,15 +41,25 @@
|
|||||||
|
|
||||||
{% if local_md_headings or local_subfolders %}
|
{% if local_md_headings or local_subfolders %}
|
||||||
<div class="local-md-headings">
|
<div class="local-md-headings">
|
||||||
<h3>Overview</h3>
|
|
||||||
<hr />
|
|
||||||
<h4 class="toctree-l1">Current Index</h4>
|
|
||||||
{% if local_md_headings %}
|
{% if local_md_headings %}
|
||||||
|
<div class="current-index" x-data x-init="typeof initCurrentNav === 'function' && initCurrentNav()">
|
||||||
|
<p class="caption" role="heading">
|
||||||
|
<span class="caption-text">Current Index</span>
|
||||||
|
</p>
|
||||||
{{ render_headings(local_md_headings) }}
|
{{ render_headings(local_md_headings) }}
|
||||||
|
<br />
|
||||||
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<h4 class="toctree-l1">File Explorer</h4>
|
|
||||||
{% if local_subfolders %}
|
{% if local_subfolders %}
|
||||||
|
<div class="full-index">
|
||||||
|
<p class="caption" role="heading">
|
||||||
|
<span class="caption-text">Full Index</span>
|
||||||
|
</p>
|
||||||
{{ render_headings(local_subfolders) }}
|
{{ render_headings(local_subfolders) }}
|
||||||
|
<br />
|
||||||
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
<script src="{{ pathto('_static/js/current-nav.js', 1) }}"></script>
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user