Skip to content

Commit ce484cf

Browse files
committed
Merge branch 'development'
Added modified extensions Lightbox and Accordion. Out-commented sections of custom.css related to switch to Accordion. Modified conf.fy to allow for extensions to function.
2 parents 5746561 + 1bcd929 commit ce484cf

File tree

18 files changed

+592
-86
lines changed

18 files changed

+592
-86
lines changed

docs/_static/custom.css

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ body {
6464
border-style: solid;
6565
}
6666

67-
/* Details expand-collaps boxes */
67+
/* Details expand-collaps boxes
6868
summary {
6969
list-style: none;
7070
display: flex;
@@ -75,11 +75,11 @@ summary {
7575
font-size: 15px;
7676
background: lightgrey;
7777
padding: 3px 2px 0 5px;
78-
}
78+
} */
7979
.wy-nav-content a {
8080
color: #666 !important;
8181
}
82-
82+
/*
8383
summary::after {
8484
content: '';
8585
width: 18px;
@@ -114,7 +114,7 @@ details {
114114
border: 1px solid #666;
115115
margin-bottom: 10px;
116116
}
117-
117+
*/
118118

119119
/* Coloring */
120120
.rst-content .note .admonition-title,

docs/conf.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import os
2+
import sys
13
# Configuration file for the modi-helper-scripts documentation site.
24
# import sphinx_rtd_theme
35

@@ -13,9 +15,12 @@
1315
# Add any Sphinx extension module names here, as strings. They can be
1416
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
1517
# ones.
18+
sys.path.insert(0, os.path.abspath('extensions'))
1619
extensions = [
1720
"sphinx_rtd_theme",
1821
"sphinxemoji.sphinxemoji",
22+
"accordion.accordion",
23+
"lightbox.lightbox"
1924
]
2025
pygments_style = 'sphinx'
2126
# Add any paths that contain templates here, relative to this directory.
@@ -39,7 +44,13 @@
3944
# Add any paths that contain custom static files (such as style sheets) here,
4045
# relative to this directory. They are copied after the builtin static files,
4146
# so a file named "default.css" will overwrite the builtin "default.css".
42-
html_static_path = ["_static"]
47+
html_static_path = [
48+
"_static",
49+
"extensions/accordion/static",
50+
"extensions/lightbox/static",
51+
"img",
52+
]
53+
html_lightbox_image_path = 'lightbox'
4354
html_css_files = ["custom.css"]
4455
# Favicon for browsertab etcetera
4556
html_favicon = '_static/favicon.ico'

docs/extensions/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
from .lightbox import setup as lightbox_setup
2+
from .accordion import setup as accordion_setup

docs/extensions/accordion/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from .accordion import setup
2+
3+
__all__ = ['setup']
Binary file not shown.
Binary file not shown.
Lines changed: 266 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,266 @@
1+
# This file is part of the MiGrid extension for Sphinx documentation.
2+
#
3+
# Accordion extension is free software: you can redistribute it and/or modify
4+
# it under the terms of the GNU General Public License as published by
5+
# the Free Software Foundation, either version 3 of the License, or
6+
# (at your option) any later version.
7+
#
8+
# Accordion extension is distributed in the hope that it will be useful,
9+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
# GNU General Public License for more details.
12+
#
13+
# You should have received a copy of the GNU General Public License
14+
# along with Aria Accordion. If not, see <https://www.gnu.org/licenses/>.
15+
16+
import os
17+
from docutils.nodes import Element, General, Text, container
18+
from sphinx.util.docutils import SphinxDirective
19+
from docutils.parsers.rst import directives
20+
21+
22+
class Details(General, Element):
23+
"""
24+
Details node representing the parent of Summary and Content.
25+
Using the details HTML element allows for HTML5 built-in accessibility.
26+
"""
27+
pass
28+
29+
30+
class Summary(General, Element):
31+
"""
32+
Summary node representing the child of Details.
33+
"""
34+
pass
35+
36+
37+
class AccordionDirective(SphinxDirective):
38+
"""
39+
Directive to create a new accordion.
40+
41+
Arguments:
42+
heading or summary of text (str): The text to display in the accordion summary.
43+
44+
Options:
45+
expand (flag): If set, the accordion will be expanded by default.
46+
47+
Example usage:
48+
.. accordion:: Summary text
49+
:expand:
50+
51+
Accordion content goes here.
52+
"""
53+
54+
has_content = True
55+
required_arguments = 1
56+
optional_arguments = 100 # Needed for optional arguments and nested elements
57+
option_spec = {'expand': directives.flag}
58+
counter = 0 # Used to generate unique IDs for accordions, needed for better accessibility
59+
60+
def run(self):
61+
"""
62+
Create a new accordion with the given summary text and content.
63+
64+
Returns:
65+
list: A list containing the Details node representing the accordion.
66+
"""
67+
self._validate_arguments()
68+
details_node = self._create_details_node()
69+
summary_node = self._create_summary_node()
70+
content_node = self._create_content_node()
71+
72+
details_node.append(summary_node)
73+
details_node.append(content_node)
74+
75+
self._set_accessibility_attributes(summary_node, content_node)
76+
77+
return [details_node]
78+
79+
def _validate_arguments(self):
80+
"""
81+
Validate the arguments passed to the directive.
82+
Raises an error if no summary text is provided.
83+
"""
84+
if not self.arguments:
85+
raise self.error('Accordion directive requires one argument: the summary text')
86+
87+
def _create_details_node(self):
88+
"""
89+
Create a new Details node and set the role and classes.
90+
91+
Returns:
92+
Details: The created Details node.
93+
"""
94+
details_node = Details()
95+
details_node['classes'].append('accordion')
96+
details_node['role'] = 'group'
97+
if 'expand' in self.options:
98+
details_node['open'] = 'open'
99+
return details_node
100+
101+
def _create_summary_node(self):
102+
"""
103+
Create a new Summary node and set the role, classes, and summary text.
104+
105+
Returns:
106+
Summary: The created Summary node.
107+
"""
108+
summary_node = Summary()
109+
summary_node['role'] = 'button'
110+
summary_node['classes'].append('accordion-summary')
111+
summary_text = ' '.join(self.arguments)
112+
summary_node.append(Text(summary_text))
113+
return summary_node
114+
115+
def _create_content_node(self):
116+
"""
117+
Create a new container node for the accordion content and parse the content.
118+
119+
Returns:
120+
container: The created container node containing the parsed content.
121+
"""
122+
content_node = container(classes=['accordion-content'])
123+
self.state.nested_parse(self.content, self.content_offset, content_node)
124+
return content_node
125+
126+
@staticmethod
127+
def _set_accessibility_attributes(summary_node, content_node):
128+
"""
129+
Set the aria-controls and aria-labelledby attributes for the summary and content nodes.
130+
131+
Args:
132+
summary_node (Summary): The Summary node.
133+
content_node (container): The container node for the accordion content.
134+
"""
135+
AccordionDirective.counter += 1
136+
content_id = f'accordion-{AccordionDirective.counter}'
137+
summary_node['aria-controls'] = content_id
138+
content_node['ids'].append(content_id)
139+
140+
141+
def visit_details(self, node):
142+
"""
143+
Visit the Details node and add the corresponding HTML element.
144+
145+
Args:
146+
node (Details): The Details node.
147+
"""
148+
attrs = {'class': 'accordion', 'role': 'region'}
149+
if 'open' in node:
150+
attrs['open'] = 'open'
151+
self.body.append(self.starttag(node, 'details', **attrs))
152+
153+
154+
def depart_details(self, _node):
155+
"""
156+
Depart the Details node and close the corresponding HTML element.
157+
"""
158+
self.body.append('</details>\n')
159+
160+
161+
def visit_summary(self, node):
162+
"""
163+
Visit the Summary node and add the corresponding HTML element.
164+
165+
Args:
166+
node (Summary): The Summary node.
167+
"""
168+
attrs = {
169+
'class': 'accordion-summary',
170+
'aria-expanded': 'true' if 'open' in node.parent else 'false'
171+
}
172+
self.body.append(self.starttag(node, 'summary', **attrs))
173+
174+
175+
def depart_summary(self, _node):
176+
"""
177+
Depart the Summary node and close the corresponding HTML element.
178+
"""
179+
self.body.append('</summary>\n')
180+
181+
182+
def latex_visit_details(self, _node):
183+
"""
184+
Visit the Details node in LaTeX and add the corresponding LaTeX command.
185+
186+
Args:
187+
_node (Details): The Details node (unused).
188+
"""
189+
self.body.append('\n\\begin{details}\n')
190+
191+
192+
def latex_depart_details(self, _node):
193+
"""
194+
Depart the Details node in LaTeX and close the corresponding LaTeX command.
195+
196+
Args:
197+
_node (Details): The Details node (unused).
198+
"""
199+
self.body.append('\n\\end{details}\n')
200+
201+
202+
def latex_visit_summary(self, _node):
203+
"""
204+
Visit the Summary node in LaTeX and add the corresponding LaTeX command.
205+
206+
Args:
207+
_node (Summary): The Summary node (unused).
208+
"""
209+
self.body.append('\\detailssummary{')
210+
211+
212+
def latex_depart_summary(self, _node):
213+
"""
214+
Depart the Summary node in LaTeX and close the corresponding LaTeX command.
215+
216+
Args:
217+
_node (Summary): The Summary node (unused).
218+
"""
219+
self.body.append('}\n')
220+
221+
222+
def setup(app):
223+
224+
"""
225+
Set up the Sphinx extension.
226+
227+
Args:
228+
app (Sphinx): The Sphinx application object.
229+
230+
Returns:
231+
dict: A dictionary containing extension metadata.
232+
"""
233+
app.add_directive('accordion', AccordionDirective)
234+
235+
# Copy CSS file
236+
237+
app.add_css_file('accordion.css')
238+
239+
app.add_node(Details,
240+
html=(visit_details, depart_details),
241+
latex=(latex_visit_details, latex_depart_details))
242+
app.add_node(Summary,
243+
html=(visit_summary, depart_summary),
244+
latex=(latex_visit_summary, latex_depart_summary))
245+
246+
return {
247+
'version': '0.1',
248+
'license': 'GPL-3.0-or-later',
249+
'author': 'Aputsiak Niels Janussen',
250+
'description': 'MiGrid extension Accordion for Sphinx documentation',
251+
'long_description': 'Accessibility focused accordion extension for Sphinx used in MiGrid User Docs',
252+
'url': 'https://github.com/aputtu/migrid-sphinx-ext',
253+
'classifiers': [
254+
'Development Status :: 3 - Alpha',
255+
'Framework :: Sphinx',
256+
'Intended Audience :: Developers and System Administrators',
257+
'License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)',
258+
'Operating System :: OS Independent',
259+
'Topic :: Documentation',
260+
'Topic :: Software Development :: Documentation',
261+
'Topic :: Software Development :: Libraries :: Python Modules',
262+
'Topic :: Text Processing :: Markup :: HTML',
263+
'Topic :: Text Processing :: Markup :: LaTeX',
264+
],
265+
'parallel_read_safe': True,
266+
}

0 commit comments

Comments
 (0)