mirror of
https://github.com/flame-engine/flame.git
synced 2025-11-03 04:18:25 +08:00
docs: Flutter-app directive can now also show the listings of code (#1500)
This commit is contained in:
@ -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%;
|
||||||
|
|||||||
@ -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');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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', '')
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user