From 0e91f5ca4d8226c14d1b0010b8179f90fd237363 Mon Sep 17 00:00:00 2001 From: Pasha Stetsenko Date: Tue, 29 Mar 2022 12:43:06 -0700 Subject: [PATCH] docs: Flutter-app directive can now also show the listings of code (#1500) --- doc/_sphinx/extensions/flutter_app.css | 44 ++++++++++++++++++++++++-- doc/_sphinx/extensions/flutter_app.js | 30 +++++++++++++----- doc/_sphinx/extensions/flutter_app.py | 38 +++++++++++++++++++--- doc/tutorials/bare_flame_game.md | 18 +++++------ doc/tutorials/klondike/step2.md | 2 +- 5 files changed, 107 insertions(+), 25 deletions(-) diff --git a/doc/_sphinx/extensions/flutter_app.css b/doc/_sphinx/extensions/flutter_app.css index 48dee1991..4b61afbfa 100644 --- a/doc/_sphinx/extensions/flutter_app.css +++ b/doc/_sphinx/extensions/flutter_app.css @@ -10,6 +10,7 @@ button.flutter-app-button { font-size: 1.1em; font-weight: bold; line-height: 1em; + margin-right: 1em; min-height: 26pt; min-width: 120pt; } @@ -33,8 +34,45 @@ button.flutter-app-button:after { 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 { - background: #00000050; + background: repeating-linear-gradient( + -45deg, + #000000bb 0px, + #000000bb 5px, + #000000aa 5px, + #000000aa 10px + ); display: none; height: 100vh; left: 0; @@ -49,8 +87,8 @@ button.flutter-app-button:after { } #flutter-app-overlay.active iframe { - border: none; - box-shadow: 0px 0px 30px 0px #ffffff26; + border: 1px solid #333; + box-shadow: 0px 0px 30px 0px #000; display: none; height: 80vh; left: 50%; diff --git a/doc/_sphinx/extensions/flutter_app.js b/doc/_sphinx/extensions/flutter_app.js index 410c57cad..face008cf 100644 --- a/doc/_sphinx/extensions/flutter_app.js +++ b/doc/_sphinx/extensions/flutter_app.js @@ -4,13 +4,7 @@ /// creates an (x) button to hide the overlay. function run_flutter_app(url) { let id = compute_iframe_id(url); - if (!$('#flutter-app-overlay').length) { - $('body').append($(` -
- -
` - )); - } + create_overlay(); if (!$('#' + id).length) { $('#flutter-app-overlay').append($( `` @@ -20,9 +14,29 @@ function run_flutter_app(url) { $('#' + 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($(` +
+ +
` + )); + } +} + /// Handler for the (x) close button on an app iframe. 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'); } diff --git a/doc/_sphinx/extensions/flutter_app.py b/doc/_sphinx/extensions/flutter_app.py index 09c5b1d47..0ecb09b34 100644 --- a/doc/_sphinx/extensions/flutter_app.py +++ b/doc/_sphinx/extensions/flutter_app.py @@ -1,4 +1,5 @@ #!/usr/bin/env python +import glob import os import re import shutil @@ -46,7 +47,8 @@ class FlutterAppDirective(SphinxDirective): "popup", and "code". 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" - (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 required_arguments = 0 @@ -91,7 +93,14 @@ class FlutterAppDirective(SphinxDirective): onclick=f'run_flutter_app("{iframe_url}")', )) 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: result.append(IFrame(src=iframe_url)) return result @@ -132,7 +141,7 @@ class FlutterAppDirective(SphinxDirective): self.logger.info('Compiling Flutter app ' + self.app_name) self._compile_source() self._copy_compiled() - self._create_index() + self._create_index_html() 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 + '/index.html') @@ -167,17 +176,38 @@ class FlutterAppDirective(SphinxDirective): dirs_exist_ok=True, ) - def _create_index(self): + def _create_index_html(self): target_file = os.path.join(self.target_dir, 'index.html') with open(target_file, 'wt') as out: out.write('\n') out.write('\n\n') out.write('\n' % (_doc_root(), self.html_dir)) out.write('%s\n' % self.app_name) + out.write('\n') out.write('\n\n') out.write('\n') out.write('\n\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(): root = os.environ.get('PUBLISH_PATH', '') diff --git a/doc/tutorials/bare_flame_game.md b/doc/tutorials/bare_flame_game.md index b18505143..50102dc17 100644 --- a/doc/tutorials/bare_flame_game.md +++ b/doc/tutorials/bare_flame_game.md @@ -1,7 +1,7 @@ # Bare Flame game -This tutorial assumes that you already have [Flutter], [git], and -[Android Studio] on your computer (all of these programs are free); and that +This tutorial assumes that you already have [Flutter], [git], and +[Android Studio] on your computer (all of these programs are free); and that you have basic familiarity with using the command line. Android Studio is not a strict requirement, you can use other IDEs too, such as [Visual Studio Code]. @@ -22,7 +22,7 @@ $ flutter doctor ``` Your output will be slightly different, but the important thing is to verify -that no errors are reported, and that your Flutter version is **2.5.0** or +that no errors are reported, and that your Flutter version is **2.5.0** or above. @@ -55,7 +55,7 @@ $ flutter create . You can verify that the project files were created successfully: ```console -$ ls +$ ls README.md android/ lib/ pubspec.yaml test/ analysis_options.yaml ios/ pubspec.lock syzygy.iml web/ ``` @@ -73,13 +73,13 @@ If you see only the `main.dart` file but not the side panel, then click the vertical `[Project]` button at the left edge of the window. Before we proceed, let's fix the view in the left panel. Locate the button -in the top left corner that says `[Android]` in the screenshot. In this +in the top left corner that says `[Android]` in the screenshot. In this dropdown select the first option "Project". Your project window should now look like this: ![](../images/tutorials/android-studio-screenshot-2.webp) -The important part is that you should be able to see all files in your +The important part is that you should be able to see all files in your project directory. @@ -110,7 +110,7 @@ After that, press the `[Pub get]` button at the top of the window; or alternatively you could run command `flutter pub get` from the terminal. This will "apply" the changes in `pubspec` file to your project, in particular it will download the Flame library which we have declared as a dependency. In the -future, you should run `flutter pub get` whenever you make changes to this +future, you should run `flutter pub get` whenever you make changes to this file. Now, open file `lib/main.dart` and replace its content with the following: @@ -138,7 +138,7 @@ selected>`. In that dropdown choose `` instead. After that open the `main.dart` file and press the green arrow next to the `void main()` function in line 4. Select `[Run main.dart]` from the menu. -This should open a new Chrome window (which may take 10-30 seconds) and run +This should open a new Chrome window (which may take 10-30 seconds) and run your project in that window. For now it will simply show a black screen, which is expected because we created the game in its simplest blank configuration. @@ -151,7 +151,7 @@ assumes that you already have a GitHub account. Log into your GitHub account, select `[Your repositories]` from your profile dropdown, and press the green `[New]` button. In the form enter repository -name the same as your project name; select type "private"; and opt out of +name the same as your project name; select type "private"; and opt out of adding initial files like README, license and gitignore. Now go to your project's directory in the terminal and execute the following diff --git a/doc/tutorials/klondike/step2.md b/doc/tutorials/klondike/step2.md index c72f8f880..95c56bff6 100644 --- a/doc/tutorials/klondike/step2.md +++ b/doc/tutorials/klondike/step2.md @@ -258,7 +258,7 @@ the card objects, which are the most important visual objects in this game. ```{flutter-app} :sources: ../tutorials/klondike/app :page: step2 -:show: popup +:show: popup code ``` [World]: ../../flame/camera_component.md#world