docs: Added ability to create infobox-style widgets in the documentation (#1771)

Additional mode "infobox" allows Flutter widgets to be inserted into the generated documentation site as wikipedia-style infoboxes floating on the right. This is useful for presenting content to the user up-front without sacrificing the flow of the exposition. For example, currently the Tap Events demo is "hidden" in the middle of a long page.

We believe that presenting the content in this way would make the user more excited to read about it.
This commit is contained in:
Pasha Stetsenko
2022-07-01 16:02:19 -07:00
committed by GitHub
parent dcdfc02762
commit 58571141bc
4 changed files with 65 additions and 29 deletions

View File

@ -44,13 +44,16 @@ class FlutterAppDirective(SphinxDirective):
with the matching name.
:show: - a list of one or more run modes, which could include "widget",
"popup", and "code". Each of these modes produces a different output:
"popup", "code", and "infobox". Each of these modes produces a different
output:
"widget" - an iframe shown directly inside the docs page;
"popup" - a [Run] button which opens the app to (almost) fullscreen;
"code" - a [Code] button which opens a popup with the code that was
compiled.
"infobox" - the content will be displayed as an infobox floating on
the right-hand side of the page.
"""
has_content = False
has_content = True
required_arguments = 0
optional_arguments = 0
option_spec = {
@ -103,6 +106,11 @@ class FlutterAppDirective(SphinxDirective):
classes=['flutter-app-button', 'code'],
onclick=f'open_code_listings("{code_id}")',
))
if 'infobox' in self.modes:
self.state.nested_parse(self.content, 0, result)
result = [
nodes.container('', *result, classes=['flutter-app-infobox'])
]
return result
def _process_show_option(self):
@ -110,7 +118,7 @@ class FlutterAppDirective(SphinxDirective):
if argument:
values = argument.split()
for value in values:
if value not in ['widget', 'popup', 'code']:
if value not in ['widget', 'popup', 'code', 'infobox']:
raise self.error('Invalid :show: value ' + value)
self.modes = values
else:
@ -228,30 +236,23 @@ def _doc_root():
# ------------------------------------------------------------------------------
class IFrame(nodes.Element, nodes.General):
pass
def visit(self, node):
self.body.append(
self.starttag(node, 'iframe', src=node.attributes['src']))
def visit_iframe(self, node):
self.body.append(self.starttag(node, 'iframe', src=node.attributes['src']))
def depart_iframe(self, _):
self.body.append('</iframe>')
def depart(self, _):
self.body.append('</iframe>')
class Button(nodes.Element, nodes.General):
pass
def visit(self, node):
attrs = {}
if 'onclick' in node.attributes:
attrs['onclick'] = node.attributes['onclick']
self.body.append(self.starttag(node, 'button', **attrs).strip())
def visit_button(self, node):
attrs = {}
if 'onclick' in node.attributes:
attrs['onclick'] = node.attributes['onclick']
self.body.append(self.starttag(node, 'button', **attrs).strip())
def depart_button(self, _):
self.body.append('</button>')
def depart(self, _):
self.body.append('</button>')
# ------------------------------------------------------------------------------
@ -265,8 +266,8 @@ def setup(app):
shutil.copy(os.path.join(base_dir, 'flutter_app.js'), target_dir)
shutil.copy(os.path.join(base_dir, 'flutter_app.css'), target_dir)
app.add_node(IFrame, html=(visit_iframe, depart_iframe))
app.add_node(Button, html=(visit_button, depart_button))
app.add_node(IFrame, html=(IFrame.visit, IFrame.depart))
app.add_node(Button, html=(Button.visit, Button.depart))
app.add_directive('flutter-app', FlutterAppDirective)
app.add_js_file('flutter_app.js')
app.add_css_file('flutter_app.css')