docs: Flutter-app directive can now also show the listings of code (#1500)

This commit is contained in:
Pasha Stetsenko
2022-03-29 12:43:06 -07:00
committed by GitHub
parent 167396142e
commit 0e91f5ca4d
5 changed files with 107 additions and 25 deletions

View File

@ -10,6 +10,7 @@ button.flutter-app-button {
font-size: 1.1em; font-size: 1.1em;
font-weight: bold; font-weight: bold;
line-height: 1em; line-height: 1em;
margin-right: 1em;
min-height: 26pt; min-height: 26pt;
min-width: 120pt; min-width: 120pt;
} }
@ -33,8 +34,45 @@ button.flutter-app-button:after {
top: 1px; top: 1px;
} }
.flutter-app-code {
display: none;
}
.flutter-app-code.active {
background: #282828;
box-shadow: 0 0 30px 0 #000;
box-sizing: border-box;
display: initial;
height: 80vh;
left: 50%;
overflow-y: scroll;
padding: 1em 2em;
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
width: 80vw;
}
.flutter-app-code .filename {
font-family: var(--font-mono);
font-size: 1.3em;
font-weight: bold;
margin: 1.5em 0 -0.5em 0;
}
.flutter-app-code div.highlight span.linenos {
color: #444;
margin-right: 8pt;
}
#flutter-app-overlay { #flutter-app-overlay {
background: #00000050; background: repeating-linear-gradient(
-45deg,
#000000bb 0px,
#000000bb 5px,
#000000aa 5px,
#000000aa 10px
);
display: none; display: none;
height: 100vh; height: 100vh;
left: 0; left: 0;
@ -49,8 +87,8 @@ button.flutter-app-button:after {
} }
#flutter-app-overlay.active iframe { #flutter-app-overlay.active iframe {
border: none; border: 1px solid #333;
box-shadow: 0px 0px 30px 0px #ffffff26; box-shadow: 0px 0px 30px 0px #000;
display: none; display: none;
height: 80vh; height: 80vh;
left: 50%; left: 50%;

View File

@ -4,13 +4,7 @@
/// creates an (x) button to hide the overlay. /// creates an (x) button to hide the overlay.
function run_flutter_app(url) { function run_flutter_app(url) {
let id = compute_iframe_id(url); let id = compute_iframe_id(url);
if (!$('#flutter-app-overlay').length) { create_overlay();
$('body').append($(`
<div id="flutter-app-overlay">
<button id="flutter-app-close-button" onclick="close_flutter_app()">✖</button>
</div>`
));
}
if (!$('#' + id).length) { if (!$('#' + id).length) {
$('#flutter-app-overlay').append($( $('#flutter-app-overlay').append($(
`<iframe id="${id}" class="flutter-app" src="${url}"></iframe>` `<iframe id="${id}" class="flutter-app" src="${url}"></iframe>`
@ -20,9 +14,29 @@ function run_flutter_app(url) {
$('#' + id).addClass('active'); $('#' + id).addClass('active');
} }
function open_code_listings(id) {
create_overlay();
if (!$('#flutter-app-overlay #' + id).length) {
$('#' + id).appendTo($('#flutter-app-overlay'));
}
$('#flutter-app-overlay').addClass('active');
$('#' + id).addClass('active');
}
function create_overlay() {
if (!$('#flutter-app-overlay').length) {
$('body').append($(`
<div id="flutter-app-overlay">
<button id="flutter-app-close-button" onclick="close_flutter_app()">✖</button>
</div>`
));
}
}
/// Handler for the (x) close button on an app iframe. /// Handler for the (x) close button on an app iframe.
function close_flutter_app() { function close_flutter_app() {
$('#flutter-app-overlay iframe').removeClass('active'); $('#flutter-app-overlay > iframe').removeClass('active');
$('#flutter-app-overlay > div').removeClass('active');
$('#flutter-app-overlay').removeClass('active'); $('#flutter-app-overlay').removeClass('active');
} }

View File

@ -1,4 +1,5 @@
#!/usr/bin/env python #!/usr/bin/env python
import glob
import os import os
import re import re
import shutil import shutil
@ -46,7 +47,8 @@ class FlutterAppDirective(SphinxDirective):
"popup", and "code". Each of these modes produces a different output: "popup", and "code". Each of these modes produces a different output:
"widget" - an iframe shown directly inside the docs page; "widget" - an iframe shown directly inside the docs page;
"popup" - a [Run] button which opens the app to (almost) fullscreen; "popup" - a [Run] button which opens the app to (almost) fullscreen;
"code" - (NYI) opens a popup showing the code that was compiled. "code" - a [Code] button which opens a popup with the code that was
compiled.
""" """
has_content = False has_content = False
required_arguments = 0 required_arguments = 0
@ -91,7 +93,14 @@ class FlutterAppDirective(SphinxDirective):
onclick=f'run_flutter_app("{iframe_url}")', onclick=f'run_flutter_app("{iframe_url}")',
)) ))
if 'code' in self.modes: if 'code' in self.modes:
pass code_id = self.app_name + "-source"
result.append(self._generate_code_listings(code_id))
result.append(Button(
'',
nodes.Text('Code'),
classes=['flutter-app-button', 'code'],
onclick=f'open_code_listings("{code_id}")',
))
if 'widget' in self.modes: if 'widget' in self.modes:
result.append(IFrame(src=iframe_url)) result.append(IFrame(src=iframe_url))
return result return result
@ -132,7 +141,7 @@ class FlutterAppDirective(SphinxDirective):
self.logger.info('Compiling Flutter app ' + self.app_name) self.logger.info('Compiling Flutter app ' + self.app_name)
self._compile_source() self._compile_source()
self._copy_compiled() self._copy_compiled()
self._create_index() self._create_index_html()
self.logger.info(' + copied into ' + self.target_dir) self.logger.info(' + copied into ' + self.target_dir)
assert os.path.isfile(self.target_dir + '/main.dart.js') assert os.path.isfile(self.target_dir + '/main.dart.js')
assert os.path.isfile(self.target_dir + '/index.html') assert os.path.isfile(self.target_dir + '/index.html')
@ -167,17 +176,38 @@ class FlutterAppDirective(SphinxDirective):
dirs_exist_ok=True, dirs_exist_ok=True,
) )
def _create_index(self): def _create_index_html(self):
target_file = os.path.join(self.target_dir, 'index.html') target_file = os.path.join(self.target_dir, 'index.html')
with open(target_file, 'wt') as out: with open(target_file, 'wt') as out:
out.write('<!DOCTYPE html>\n') out.write('<!DOCTYPE html>\n')
out.write('<html>\n<head>\n') out.write('<html>\n<head>\n')
out.write('<base href="%s%s/">\n' % (_doc_root(), self.html_dir)) out.write('<base href="%s%s/">\n' % (_doc_root(), self.html_dir))
out.write('<title>%s</title>\n' % self.app_name) out.write('<title>%s</title>\n' % self.app_name)
out.write('<style>body { background: black; }</style>\n')
out.write('</head>\n<body>\n') out.write('</head>\n<body>\n')
out.write('<script src="main.dart.js"></script>\n') out.write('<script src="main.dart.js"></script>\n')
out.write('</body>\n</html>\n') out.write('</body>\n</html>\n')
def _generate_code_listings(self, code_id):
code_dir = self.source_dir + '/lib/' + self.options.get('page', '')
if not os.path.isdir(code_dir):
raise self.error('Cannot find source directory ' + code_dir)
files = glob.glob(code_dir + '/**', recursive=True)
result = nodes.container(classes=['flutter-app-code'], ids=[code_id])
for filename in sorted(files):
if os.path.isfile(filename):
simple_filename = os.path.relpath(filename, code_dir)
result += nodes.container(
'', nodes.Text(simple_filename), classes=['filename']
)
with open(filename, 'rt') as f:
self.state.nested_parse(
['``````{code-block} dart\n:lineno-start: 1\n'] +
[line.rstrip() for line in f] +
['``````\n'], 0, result)
return result
def _doc_root(): def _doc_root():
root = os.environ.get('PUBLISH_PATH', '') root = os.environ.get('PUBLISH_PATH', '')

View File

@ -258,7 +258,7 @@ the card objects, which are the most important visual objects in this game.
```{flutter-app} ```{flutter-app}
:sources: ../tutorials/klondike/app :sources: ../tutorials/klondike/app
:page: step2 :page: step2
:show: popup :show: popup code
``` ```
[World]: ../../flame/camera_component.md#world [World]: ../../flame/camera_component.md#world