moodle-docs-theme 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,92 @@
1
+ """
2
+ moodle_docs_theme - A reusable Sphinx HTML theme inspired by docs.moodle.org (MoodleDocs).
3
+ """
4
+
5
+ import os
6
+ from typing import Dict, Any
7
+
8
+ __version__ = "0.1.0"
9
+
10
+
11
+ def get_html_theme_path() -> str:
12
+ """
13
+ Return the absolute path to the directory containing theme.conf.
14
+
15
+ This function is maintained for backward compatibility with older Sphinx theme patterns.
16
+ Modern Sphinx 1.6+ discovers the theme automatically via entry points.
17
+ """
18
+ return os.path.abspath(os.path.dirname(__file__))
19
+
20
+
21
+ def validate_github_actions_config(app: Any) -> None:
22
+ """
23
+ Validate Sphinx configuration when running inside GitHub Actions.
24
+
25
+ If GITHUB_ACTIONS == 'true', ensures that:
26
+ 1. 'moodle_docs_theme' is present in app.config.extensions
27
+ 2. 'sphinx.ext.githubpages' is present in app.config.extensions
28
+
29
+ Raises ExtensionError if requirements are not met.
30
+ """
31
+ is_github_actions = (
32
+ os.environ.get("GITHUB_ACTIONS") == "true" or "GITHUB_RUN_ID" in os.environ
33
+ )
34
+
35
+ if not is_github_actions:
36
+ return
37
+
38
+ extensions = getattr(app.config, "extensions", []) or []
39
+ missing_requirements = []
40
+
41
+ if "moodle_docs_theme" not in extensions:
42
+ missing_requirements.append(
43
+ "• 'moodle_docs_theme' deve estar listado em 'extensions = [...]' no seu docs/conf.py."
44
+ )
45
+
46
+ if "sphinx.ext.githubpages" not in extensions:
47
+ missing_requirements.append(
48
+ "• 'sphinx.ext.githubpages' deve estar listado em 'extensions = [...]' no seu docs/conf.py para gerar o arquivo .nojekyll e evitar que o GitHub Pages bloqueie a pasta _static/."
49
+ )
50
+
51
+ if missing_requirements:
52
+ error_msg = (
53
+ "\n"
54
+ "================================================================================\n"
55
+ "[moodle_docs_theme] ERRO DE CONFIGURAÇÃO NO GITHUB ACTIONS\n"
56
+ "================================================================================\n"
57
+ "Foi detectada a execução dentro do ambiente GitHub Actions, mas as configurações\n"
58
+ "obrigatórias do tema não foram encontradas no seu 'docs/conf.py':\n\n"
59
+ + "\n".join(missing_requirements)
60
+ + "\n\n"
61
+ "Por favor, certifique-se de atualizar o 'docs/conf.py' do seu projeto:\n\n"
62
+ " extensions = [\n"
63
+ " 'sphinx.ext.autodoc',\n"
64
+ " 'sphinx.ext.githubpages',\n"
65
+ " 'moodle_docs_theme',\n"
66
+ " ]\n\n"
67
+ "================================================================================\n"
68
+ )
69
+ from sphinx.errors import ExtensionError
70
+ raise ExtensionError(error_msg)
71
+
72
+
73
+ def setup(app: Any) -> Dict[str, Any]:
74
+ """
75
+ Sphinx extension setup function.
76
+
77
+ Registers the theme with Sphinx when activated in conf.py.
78
+ """
79
+ theme_path = get_html_theme_path()
80
+ app.add_html_theme("moodle_docs_theme", theme_path)
81
+
82
+ app.add_css_file("css/colors.css")
83
+ app.add_css_file("css/base.css")
84
+ app.add_js_file("js/theme.js")
85
+
86
+ app.connect("builder-inited", validate_github_actions_config)
87
+
88
+ return {
89
+ "version": __version__,
90
+ "parallel_read_safe": True,
91
+ "parallel_write_safe": True,
92
+ }
@@ -0,0 +1,38 @@
1
+ {# Breadcrumbs navigation bar #}
2
+ <div class="moodle-breadcrumbs-bar">
3
+ <div class="moodle-breadcrumbs-inner">
4
+ <nav aria-label="Breadcrumbs">
5
+ <ul class="moodle-breadcrumbs">
6
+ <li>
7
+ <a href="{{ pathto(master_doc) }}">{{ _('Início') }}</a>
8
+ </li>
9
+ {% for parent in parents %}
10
+ <li>
11
+ <a href="{{ parent.link|e }}">{{ parent.title }}</a>
12
+ </li>
13
+ {% endfor %}
14
+ {% if pagename != master_doc %}
15
+ <li aria-current="page">
16
+ <span>{{ title|striptags }}</span>
17
+ </li>
18
+ {% endif %}
19
+ </ul>
20
+ </nav>
21
+
22
+ {# Edit on GitHub link #}
23
+ {% if theme_show_edit_on_github|tobool and (theme_github_url or theme_github_repo) %}
24
+ {% set gh_repo = theme_github_repo if theme_github_repo else (theme_github_url.rstrip('/').split('/')[-2:] | join('/')) %}
25
+ {% set gh_version = theme_github_version if theme_github_version else 'main' %}
26
+ {% set gh_doc_path = theme_doc_path if theme_doc_path else 'docs/' %}
27
+ {% set file_ext = page_source_suffix if page_source_suffix and page_source_suffix is string else '.rst' %}
28
+ {% set edit_url = "https://github.com/" ~ gh_repo ~ "/edit/" ~ gh_version ~ "/" ~ gh_doc_path.rstrip('/') ~ "/" ~ pagename ~ file_ext %}
29
+ <a href="{{ edit_url }}" class="edit-on-github-link" target="_blank" rel="noopener noreferrer" title="Editar esta página no GitHub">
30
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
31
+ <path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"></path>
32
+ <path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"></path>
33
+ </svg>
34
+ <span>Editar no GitHub</span>
35
+ </a>
36
+ {% endif %}
37
+ </div>
38
+ </div>
@@ -0,0 +1,179 @@
1
+ {% extends "basic/layout.html" %}
2
+
3
+ {% block doctype %}
4
+ <!DOCTYPE html>
5
+ {% endblock %}
6
+
7
+ {% block htmltag %}
8
+ <html lang="{{ language if language else 'pt-BR' }}">
9
+ {% endblock %}
10
+
11
+ {% block extrahead %}
12
+ {{ super() }}
13
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
14
+
15
+ {# Script inline de inicialização instantânea do Dark Mode (Evita FOUC) #}
16
+ <script>
17
+ (function() {
18
+ try {
19
+ var storedTheme = localStorage.getItem('moodle-theme');
20
+ var systemPrefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
21
+ var theme = storedTheme || (systemPrefersDark ? 'dark' : 'light');
22
+ if (theme === 'dark') {
23
+ document.documentElement.setAttribute('data-theme', 'dark');
24
+ } else {
25
+ document.documentElement.removeAttribute('data-theme');
26
+ }
27
+ } catch (e) {}
28
+ })();
29
+ </script>
30
+
31
+ {# Carregamento da fonte Open Sans via Google Fonts (mesma família usada no docs.moodle.org) #}
32
+ <link rel="preconnect" href="https://fonts.googleapis.com">
33
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
34
+ <link href="https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300;0,400;0,600;0,700;1,400&display=swap" rel="stylesheet">
35
+
36
+ {# Dynamic CSS Variable overrides from theme_options #}
37
+ <style>
38
+ :root {
39
+ {% if theme_primary_color %}--moodle-primary: {{ theme_primary_color }};{% endif %}
40
+ {% if theme_secondary_color %}--moodle-accent: {{ theme_secondary_color }}; --moodle-header-border: {{ theme_secondary_color }};{% endif %}
41
+ {% if theme_accent_color %}--moodle-sub-header-bg: {{ theme_accent_color }};{% endif %}
42
+ {% if theme_text_color %}--moodle-text: {{ theme_text_color }};{% endif %}
43
+ {% if theme_bg_color %}--moodle-bg: {{ theme_bg_color }};{% endif %}
44
+ {% if theme_code_bg_color %}--moodle-code-bg: {{ theme_code_bg_color }};{% endif %}
45
+ {% if theme_link_color %}--moodle-link: {{ theme_link_color }};{% endif %}
46
+ {% if theme_link_hover_color %}--moodle-link-hover: {{ theme_link_hover_color }};{% endif %}
47
+ {% if theme_sidebar_bg %}--moodle-sidebar-bg: {{ theme_sidebar_bg }};{% endif %}
48
+ {% if theme_nav_text_color %}--moodle-nav-text: {{ theme_nav_text_color }};{% endif %}
49
+ }
50
+ </style>
51
+ {% endblock %}
52
+
53
+ {% block header %}
54
+ <div class="moodle-site-wrapper">
55
+ {# 1. Top Header Bar (Estilo MoodleDocs: fundo claro, marca à esquerda, faixa laranja inferior) #}
56
+ <header class="moodle-header">
57
+ <div class="moodle-header-inner">
58
+ {# Brand Logo & Name #}
59
+ <div class="moodle-brand-group">
60
+ <a href="{{ pathto(master_doc) }}" class="moodle-brand">
61
+ {% if theme_logo %}
62
+ <img src="{{ pathto('_static/' ~ theme_logo, 1) }}" alt="{{ project }}" class="moodle-brand-logo" style="{% if theme_logo_height %}height: {{ theme_logo_height }};{% endif %}" />
63
+ {% elif logo_url %}
64
+ <img src="{{ logo_url }}" alt="{{ project }}" class="moodle-brand-logo" />
65
+ {% elif logo %}
66
+ <img src="{{ pathto('_static/' ~ logo, 1) }}" alt="{{ project }}" class="moodle-brand-logo" />
67
+ {% else %}
68
+ <span class="moodle-brand-title">
69
+ {% if theme_project_name %}{{ theme_project_name }}{% else %}{{ project }}{% endif %}
70
+ </span>
71
+ {% endif %}
72
+ </a>
73
+ <span class="moodle-tagline">
74
+ {% if theme_tagline %}{{ theme_tagline }}{% else %}Documentação inspirada no MoodleDocs{% endif %}
75
+ </span>
76
+ </div>
77
+
78
+ {# Right-side tools: Header Search & Dark Mode Toggle #}
79
+ <div class="moodle-header-tools">
80
+ <form action="{{ pathto('search') }}" method="get" class="moodle-header-search">
81
+ <input type="text" name="q" placeholder="Buscar..." aria-label="Buscar na documentação" required />
82
+ <input type="hidden" name="check_keywords" value="yes" />
83
+ <input type="hidden" name="area" value="default" />
84
+ <button type="submit" title="Buscar">🔍</button>
85
+ </form>
86
+
87
+ {% if theme_enable_dark_mode|tobool %}
88
+ <button id="theme-toggle" class="theme-toggle-btn" aria-label="Alternar modo claro/escuro" title="Alternar modo claro/escuro">
89
+ <span id="theme-toggle-icon">🌙</span>
90
+ </button>
91
+ {% endif %}
92
+ </div>
93
+ </div>
94
+ </header>
95
+
96
+ {# 2. Sub-Header Banner Strip (Estilo barra de contexto do MoodleDocs) #}
97
+ <section class="moodle-sub-header">
98
+ <div class="moodle-sub-header-inner">
99
+ <div class="moodle-sub-header-title">
100
+ <span>Documentação</span>
101
+ {% if release %}
102
+ <span class="moodle-version-badge">v{{ release }}</span>
103
+ {% endif %}
104
+ </div>
105
+ <div>
106
+ {% if theme_github_url %}
107
+ <a href="{{ theme_github_url }}" class="moodle-sub-header-link" target="_blank" rel="noopener noreferrer">Repositório no GitHub ↗</a>
108
+ {% endif %}
109
+ </div>
110
+ </div>
111
+ </section>
112
+ {% endblock %}
113
+
114
+ {% block content %}
115
+ {# 3. Main Layout Container (Artigo na ESQUERDA, Navegação na DIREITA, como no docs.moodle.org) #}
116
+ <div class="moodle-main-container">
117
+ {# Main Article Content (Esquerda) #}
118
+ <main class="moodle-content" role="main">
119
+ {% block body %}{% endblock %}
120
+ </main>
121
+
122
+ {# Sidebar Navegação (DIREITA - Estilo MoodleDocs) #}
123
+ {% block sidebar1 %}
124
+ <aside class="moodle-sidebar" id="moodle-sidebar" role="navigation" aria-label="Navegação Principal">
125
+ {% if theme_navigation_links %}
126
+ <div class="moodle-sidebar-section-title">Seções &amp; Links</div>
127
+ <nav>
128
+ <ul>
129
+ {% if theme_navigation_links is string %}
130
+ {% for item in theme_navigation_links.split(',') %}
131
+ {% set parts = item.strip().split('|') %}
132
+ {% set title = parts[0].strip() %}
133
+ {% set target = parts[1].strip() if parts|length > 1 else master_doc %}
134
+ <li class="{% if pagename in target or (target == master_doc and pagename == master_doc) %}current{% endif %}">
135
+ {% if target.startswith('http://') or target.startswith('https://') %}
136
+ <a href="{{ target }}" target="_blank" rel="noopener noreferrer">{{ title }} ↗</a>
137
+ {% else %}
138
+ {% set clean_target = target[:-5] if target.endswith('.html') else target %}
139
+ <a href="{{ pathto(clean_target) }}" class="{% if pagename == clean_target %}current{% endif %}">{{ title }}</a>
140
+ {% endif %}
141
+ </li>
142
+ {% endfor %}
143
+ {% endif %}
144
+ </ul>
145
+ </nav>
146
+ {% endif %}
147
+ </aside>
148
+ {% endblock %}
149
+ </div>
150
+ {% endblock %}
151
+
152
+ {% block footer %}
153
+ {# Footer #}
154
+ <footer class="moodle-footer" role="contentinfo">
155
+ <div class="moodle-footer-inner">
156
+ <div>
157
+ {% if copyright %}
158
+ &copy; {{ copyright }}.
159
+ {% else %}
160
+ &copy; {{ last_updated_year if last_updated_year else '' }} {{ project }}.
161
+ {% endif %}
162
+ {% if theme_footer_custom_text %}
163
+ {{ theme_footer_custom_text }}
164
+ {% endif %}
165
+ </div>
166
+ <div>
167
+ Desenvolvido com inspiração na documentação oficial do
168
+ <a href="https://docs.moodle.org/" target="_blank" rel="noopener noreferrer">MoodleDocs</a> &amp;
169
+ <a href="https://www.sphinx-doc.org/" target="_blank" rel="noopener noreferrer">Sphinx</a>.
170
+ </div>
171
+ {% if theme_github_url %}
172
+ <div>
173
+ <a href="{{ theme_github_url }}" target="_blank" rel="noopener noreferrer">Ver código no GitHub</a>
174
+ </div>
175
+ {% endif %}
176
+ </div>
177
+ </footer>
178
+ </div> {# End site wrapper #}
179
+ {% endblock %}
@@ -0,0 +1,7 @@
1
+ {% extends "layout.html" %}
2
+
3
+ {% block body %}
4
+ <article class="moodle-page">
5
+ {{ body }}
6
+ </article>
7
+ {% endblock %}
@@ -0,0 +1,9 @@
1
+ {# Searchbox component for moodle_docs_theme #}
2
+ <div class="moodle-searchbox" role="search">
3
+ <div class="moodle-sidebar-section-title">Buscar</div>
4
+ <form action="{{ pathto('search') }}" method="get">
5
+ <input type="text" name="q" placeholder="Buscar na documentação..." aria-label="Buscar na documentação" required />
6
+ <input type="hidden" name="check_keywords" value="yes" />
7
+ <input type="hidden" name="area" value="default" />
8
+ </form>
9
+ </div>