Minor sample index cleanup (#1532)

pull/1535/head
Parker Lougheed 2 years ago committed by GitHub
parent 7e11b89445
commit 9a82e003ba
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -7,9 +7,9 @@ import 'package:path/path.dart' as p;
import 'common.dart'; import 'common.dart';
import 'fix_base_tags.dart'; import 'fix_base_tags.dart';
final ignoredDirectories = ['_tool', 'samples_index']; const ignoredDirectories = ['_tool', 'samples_index'];
main() async { void main() async {
final packageDirs = [ final packageDirs = [
...listPackageDirs(Directory.current) ...listPackageDirs(Directory.current)
.map((path) => p.relative(path, from: Directory.current.path)) .map((path) => p.relative(path, from: Directory.current.path))

@ -14,7 +14,7 @@ import 'package:path/path.dart' as p;
import 'common.dart'; import 'common.dart';
main(List<String> args) async { void main(List<String> args) async {
final buildDir = args[0]; final buildDir = args[0];
final fileMap = final fileMap =
(jsonDecode(args[1]) as Map<String, dynamic>).cast<String, String>(); (jsonDecode(args[1]) as Map<String, dynamic>).cast<String, String>();

@ -2,7 +2,7 @@ name: tool
publish_to: none publish_to: none
environment: environment:
sdk: '>=2.12.0 <3.0.0' sdk: '>=2.17.0 <3.0.0'
dependencies: dependencies:
markdown: ^6.0.0 markdown: ^6.0.0

@ -3,7 +3,6 @@ public/
# Files and directories created by pub # Files and directories created by pub
.dart_tool/ .dart_tool/
.packages
# Remove the following pattern if you wish to check in your lock file # Remove the following pattern if you wish to check in your lock file
pubspec.lock pubspec.lock

@ -7,9 +7,8 @@ This tool is used to generate the visual samples index for Flutter samples.
We use [grinder](https://pub.dev/packages/grinder) to run the build tasks: We use [grinder](https://pub.dev/packages/grinder) to run the build tasks:
```bash ```bash
$ pub get $ dart pub get
$ pub global activate grinder $ dart run grinder generate
$ grind generate
``` ```
This will generate the index into `./web` This will generate the index into `./web`
@ -20,6 +19,7 @@ If you want to serve the index locally, you can use
[webdev](https://pub.dev/packages/webdev): [webdev](https://pub.dev/packages/webdev):
```bash ```bash
$ dart pub global activate grinder
$ webdev serve $ webdev serve
``` ```
@ -28,16 +28,16 @@ $ webdev serve
You can build the complete index into a publishable directory using Grinder: You can build the complete index into a publishable directory using Grinder:
```bash ```bash
$ grind build-release $ dart run grinder build-release
``` ```
This outputs the completely built index to `./public`. This outputs the completely built index to `./public`.
## Generating cookbook content ## Generating cookbook content
The cookbook articles are generated using a WebDriver script that scrapes the The cookbook articles are generated using a WebDriver script
flutter.dev website. To run: that scrapes the docs.flutter.dev website. To run:
1. Install [ChromeDriver](https://chromedriver.chromium.org/downloads) 1. Install [ChromeDriver](https://chromedriver.chromium.org/downloads)
2. run `chromedriver --port=4444 --url-base=wd/hub --verbose` 2. run `chromedriver --port=4444 --url-base=wd/hub --verbose`
3. run `grind scrape-cookbook` 3. run `dart run grinder scrape-cookbook`

@ -6,6 +6,7 @@ analyzer:
language: language:
strict-casts: true strict-casts: true
strict-inference: true strict-inference: true
strict-raw-types: true
linter: linter:
rules: rules:
@ -16,6 +17,11 @@ linter:
directives_ordering: true directives_ordering: true
package_api_docs: true package_api_docs: true
package_prefixed_library_names: true package_prefixed_library_names: true
prefer_final_in_for_each: true
prefer_single_quotes: true
test_types_in_equals: true test_types_in_equals: true
throw_in_finally: true throw_in_finally: true
unawaited_futures: true
unnecessary_statements: true unnecessary_statements: true
use_enums: true
use_super_parameters: true

@ -14,11 +14,11 @@ import 'package:webdriver/io.dart';
class CookbookScraper { class CookbookScraper {
late WebDriver _driver; late WebDriver _driver;
Future init() async { Future<void> init() async {
_driver = await createDriver(desired: <String, dynamic>{}); _driver = await createDriver(desired: <String, dynamic>{});
} }
Future dispose() async { Future<void> dispose() async {
await _driver.quit(); await _driver.quit();
} }
@ -59,7 +59,7 @@ class CookbookScraper {
); );
} }
Future takeScreenshot(String url) async { Future<void> takeScreenshot(String url) async {
var screenshot = await _driver.captureScreenshotAsList(); var screenshot = await _driver.captureScreenshotAsList();
var file = File('web/${screenshotPath(url)}'); var file = File('web/${screenshotPath(url)}');
await file.create(recursive: true); await file.create(recursive: true);

@ -11,7 +11,7 @@ class Carousel {
final List<Element> slides = querySelectorAll('.slider-single'); final List<Element> slides = querySelectorAll('.slider-single');
late int currentSlideIndex; late int currentSlideIndex;
late int lastSlideIndex; late final int lastSlideIndex;
late Element prevSlide, currentSlide, nextSlide; late Element prevSlide, currentSlide, nextSlide;
@ -127,24 +127,24 @@ class Carousel {
} }
void _checkRepeat() { void _checkRepeat() {
var prevArrow = querySelector('.slider-left'); var prevArrow = querySelector('.slider-left') as AnchorElement;
var nextArrow = querySelector('.slider-right'); var nextArrow = querySelector('.slider-right') as AnchorElement;
if (currentSlideIndex == slides.length - 1) { if (currentSlideIndex == slides.length - 1) {
slides[0].classes.add('hidden'); slides[0].classes.add('hidden');
slides[slides.length - 1].classes.remove('hidden'); slides[slides.length - 1].classes.remove('hidden');
prevArrow!.classes.remove('hidden'); prevArrow.classes.remove('hidden');
nextArrow!.classes.add('hidden'); nextArrow.classes.add('hidden');
} else if (currentSlideIndex == 0) { } else if (currentSlideIndex == 0) {
slides[slides.length - 1].classes.add('hidden'); slides[slides.length - 1].classes.add('hidden');
slides[0].classes.remove('hidden'); slides[0].classes.remove('hidden');
prevArrow!.classes.add('hidden'); prevArrow.classes.add('hidden');
nextArrow!.classes.remove('hidden'); nextArrow.classes.remove('hidden');
} else { } else {
slides[slides.length - 1].classes.remove('hidden'); slides[slides.length - 1].classes.remove('hidden');
slides[0].classes.remove('hidden'); slides[0].classes.remove('hidden');
prevArrow!.classes.remove('hidden'); prevArrow.classes.remove('hidden');
nextArrow!.classes.remove('hidden'); nextArrow.classes.remove('hidden');
} }
} }

@ -22,7 +22,7 @@ class Index {
Index(this.samples); Index(this.samples);
factory Index.fromJson(Map json) => _$IndexFromJson(json); factory Index.fromJson(Map<dynamic, dynamic> json) => _$IndexFromJson(json);
Map<String, dynamic> toJson() => _$IndexToJson(this); Map<String, dynamic> toJson() => _$IndexToJson(this);
} }
@ -100,7 +100,7 @@ class Sample {
this.channel, this.channel,
}); });
factory Sample.fromJson(Map json) => _$SampleFromJson(json); factory Sample.fromJson(Map<dynamic, dynamic> json) => _$SampleFromJson(json);
Map<String, dynamic> toJson() => _$SampleToJson(this); Map<String, dynamic> toJson() => _$SampleToJson(this);
@ -116,25 +116,25 @@ class Sample {
buf.write(name.toLowerCase()); buf.write(name.toLowerCase());
buf.write(' '); buf.write(' ');
for (var tag in tags) { for (final tag in tags) {
buf.write('tag:${tag.toLowerCase()} '); buf.write('tag:${tag.toLowerCase()} ');
// Allow tags to be searched without the tag: prefix // Allow tags to be searched without the tag: prefix
buf.write('${tag.toLowerCase()} '); buf.write('${tag.toLowerCase()} ');
} }
for (var platform in platforms) { for (final platform in platforms) {
buf.write('platform:$platform '); buf.write('platform:$platform ');
// Allow platforms to be searched without the tag: prefix // Allow platforms to be searched without the tag: prefix
buf.write('$platform '); buf.write('$platform ');
} }
for (var widget in widgets) { for (final widget in widgets) {
buf.write('widget:$widget '); buf.write('widget:$widget ');
} }
for (var package in packages) { for (final package in packages) {
buf.write('package:$package '); buf.write('package:$package ');
} }
@ -167,7 +167,8 @@ class Screenshot {
Screenshot(this.url, this.alt); Screenshot(this.url, this.alt);
factory Screenshot.fromJson(Map json) => _$ScreenshotFromJson(json); factory Screenshot.fromJson(Map<dynamic, dynamic> json) =>
_$ScreenshotFromJson(json);
Map<String, dynamic> toJson() => _$ScreenshotToJson(this); Map<String, dynamic> toJson() => _$ScreenshotToJson(this);
} }
@ -180,7 +181,7 @@ class Link {
Link(this.text, this.href); Link(this.text, this.href);
factory Link.fromJson(Map json) => _$LinkFromJson(json); factory Link.fromJson(Map<dynamic, dynamic> json) => _$LinkFromJson(json);
Map<String, dynamic> toJson() => _$LinkToJson(this); Map<String, dynamic> toJson() => _$LinkToJson(this);
} }

@ -16,7 +16,7 @@ bool matchesQuery(String query, String sampleAttributes) {
// This will check whether a type parameter is present in the // This will check whether a type parameter is present in the
// search query, and return false if the self type mismatches // search query, and return false if the self type mismatches
// the query type // the query type
for (var word in queryWords) { for (final word in queryWords) {
if ((word.contains('type:') && !attributes.contains(word)) || if ((word.contains('type:') && !attributes.contains(word)) ||
(word.contains('platform:') && !attributes.contains('type:demo'))) { (word.contains('platform:') && !attributes.contains('type:demo'))) {
return false; return false;
@ -30,7 +30,7 @@ bool matchesQuery(String query, String sampleAttributes) {
// Test for exact matches for keywords // Test for exact matches for keywords
var matches = 0; var matches = 0;
for (var word in queryWords) { for (final word in queryWords) {
if (attributes.contains(word)) { if (attributes.contains(word)) {
matches++; matches++;
} }
@ -43,8 +43,8 @@ bool matchesQuery(String query, String sampleAttributes) {
// e.g. searching "kitten tag:cats" is a match for a sample with the // e.g. searching "kitten tag:cats" is a match for a sample with the
// attributes "kittens tag:cats" // attributes "kittens tag:cats"
matches = 0; matches = 0;
for (var attribute in attributes) { for (final attribute in attributes) {
for (var queryWord in queryWords) { for (final queryWord in queryWords) {
if (attribute.startsWith(queryWord)) { if (attribute.startsWith(queryWord)) {
matches++; matches++;
} }

@ -29,7 +29,7 @@ $_footer
</html> </html>
'''; ''';
String _indexHeader = ''' const String _indexHeader = '''
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>Flutter samples</title> <title>Flutter samples</title>
@ -39,11 +39,11 @@ String _indexHeader = '''
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<script src="packages/mdc_web/material-components-web.min.js"></script> <script src="packages/mdc_web/material-components-web.min.js"></script>
<script defer src="main.dart.js"></script> <script defer src="main.dart.js"></script>
${_googleAnalytics()} $_googleAnalytics
</head> </head>
'''; ''';
String _descriptionHeader = ''' const String _descriptionHeader = '''
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>Flutter samples</title> <title>Flutter samples</title>
@ -54,11 +54,11 @@ String _descriptionHeader = '''
<script src="packages/mdc_web/material-components-web.min.js"></script> <script src="packages/mdc_web/material-components-web.min.js"></script>
<script src="https://kit.fontawesome.com/16cc04762e.js"></script> <script src="https://kit.fontawesome.com/16cc04762e.js"></script>
<script defer src="description.dart.js"></script> <script defer src="description.dart.js"></script>
${_googleAnalytics()} $_googleAnalytics
</head> </head>
'''; ''';
String _navbar = ''' const String _navbar = '''
<div class="navbar"> <div class="navbar">
<a class="leading" href="./"> <a class="leading" href="./">
<img src="images/logos/logo_lockup_flutter_horizontal_wht_96.png" /> <img src="images/logos/logo_lockup_flutter_horizontal_wht_96.png" />
@ -189,9 +189,10 @@ String _descriptionPage(Sample sample) => '''
String _descriptionButtons(Sample sample) { String _descriptionButtons(Sample sample) {
var buf = StringBuffer(); var buf = StringBuffer();
if (sample.web?.isNotEmpty == true) { var sampleLink = sample.web;
if (sampleLink != null && sampleLink.isNotEmpty) {
buf.write( buf.write(
'''<button class="mdc-button mdc-button--outlined" onclick="window.location.href = '${sample.web}';"><span class="mdc-button__ripple"></span> Launch App</button>'''); '''<button class="mdc-button mdc-button--outlined" onclick="window.location.href = '$sampleLink';"><span class="mdc-button__ripple"></span> Launch App</button>''');
} }
if (sample.type == 'app' || if (sample.type == 'app' ||
@ -214,7 +215,7 @@ String _descriptionButtons(Sample sample) {
String _tags(Sample sample) { String _tags(Sample sample) {
var buf = StringBuffer(); var buf = StringBuffer();
for (var tag in sample.tags) { for (final tag in sample.tags) {
buf.write('<a href="./#?search=tag%3A$tag">$tag</a>\n'); buf.write('<a href="./#?search=tag%3A$tag">$tag</a>\n');
} }
return buf.toString(); return buf.toString();
@ -222,7 +223,7 @@ String _tags(Sample sample) {
String _descriptionScreenshots(Sample sample) { String _descriptionScreenshots(Sample sample) {
var buf = StringBuffer(); var buf = StringBuffer();
for (var screenshot in sample.screenshots) { for (final screenshot in sample.screenshots) {
buf.write( buf.write(
'''<div class="slider-single"><img class="slider-single-image" src="${screenshot.url}" alt="${screenshot.alt}" /></div>\n'''); '''<div class="slider-single"><img class="slider-single-image" src="${screenshot.url}" alt="${screenshot.alt}" /></div>\n''');
} }
@ -233,8 +234,7 @@ String _descriptionText(Sample sample) {
return '<p>${sample.description}</p>'; return '<p>${sample.description}</p>';
} }
String _googleAnalytics() { const String _googleAnalytics = """
return """
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-67589403-8"></script> <script async src="https://www.googletagmanager.com/gtag/js?id=UA-67589403-8"></script>
<script> <script>
window.dataLayer = window.dataLayer || []; window.dataLayer = window.dataLayer || [];
@ -242,4 +242,3 @@ String _googleAnalytics() {
gtag('js', new Date()); gtag('js', new Date());
gtag('config', 'UA-67589403-8'); gtag('config', 'UA-67589403-8');
</script>"""; </script>""";
}

@ -1,13 +1,15 @@
name: samples_index name: samples_index
description: A visual index of Flutter samples description: A visual index of Flutter samples
homepage: https://github.com/flutter/samples_index homepage: https://github.com/flutter/samples/tree/main/web/samples_index
version: 0.0.1 version: 0.0.1
environment: environment:
sdk: ">=2.12.0 <3.0.0" sdk: '>=2.17.0 <3.0.0'
dependencies: dependencies:
json_annotation: ^4.0.1 json_annotation: ^4.7.0
path: ^1.6.0 path: ^1.8.0
yaml: ^3.0.0 yaml: ^3.1.0
mdc_web: ^0.6.0 mdc_web: ^0.6.0
# ^2.1.5 is no longer compatible with our overridden sass version # ^2.1.5 is no longer compatible with our overridden sass version
# https://github.com/flutter/samples/issues/1472 # https://github.com/flutter/samples/issues/1472
@ -15,15 +17,17 @@ dependencies:
checked_yaml: ^2.0.1 checked_yaml: ^2.0.1
webdriver: ^3.0.0 webdriver: ^3.0.0
html: ^0.15.0 html: ^0.15.0
dev_dependencies: dev_dependencies:
grinder: ^0.9.0 grinder: ^0.9.0
flutter_lints: ^2.0.1 flutter_lints: ^2.0.1
test: ^1.17.10 test: ^1.12.0
json_serializable: ^6.1.5 json_serializable: ^6.5.0
build: ^2.0.3 build: ^2.3.0
build_runner: ^2.0.6 build_runner: ^2.3.0
build_web_compilers: ^3.0.0 build_web_compilers: ^3.2.0
image: ^3.0.2 image: ^3.2.0
# waiting for the next material-components-web release. # waiting for the next material-components-web release.
# Once released, it will need to be rolled into package:mdc_web. # Once released, it will need to be rolled into package:mdc_web.
# #

@ -48,8 +48,8 @@ Future<void> generate() async {
var outputFile = File('web/index.html'); var outputFile = File('web/index.html');
await outputFile.create(recursive: true); await outputFile.create(recursive: true);
await outputFile.writeAsString(templates.index(samples)); await outputFile.writeAsString(templates.index(samples));
var futures = <Future>[]; var futures = <Future<void>>[];
for (var sample in samples) { for (final sample in samples) {
var file = File('web/${sample.filename}.html'); var file = File('web/${sample.filename}.html');
var future = file.create(recursive: true).then((_) async { var future = file.create(recursive: true).then((_) async {
await file.writeAsString(templates.description(sample)); await file.writeAsString(templates.description(sample));
@ -71,7 +71,7 @@ Future<void> scrapeCookbook() async {
var links = await scraper.fetchCookbookLinks(); var links = await scraper.fetchCookbookLinks();
log('Scraping ${links.length} cookbook articles'); log('Scraping ${links.length} cookbook articles');
var allSamples = <Sample>[]; var allSamples = <Sample>[];
for (var link in links) { for (final link in links) {
allSamples.add(await scraper.getMetadata(link)); allSamples.add(await scraper.getMetadata(link));
await scraper.takeScreenshot(link); await scraper.takeScreenshot(link);
} }
@ -95,9 +95,9 @@ Future<void> createThumbnails() async {
// Creates a thumbnail image for each png file // Creates a thumbnail image for each png file
Future<void> _createThumbnails(Directory directory) async { Future<void> _createThumbnails(Directory directory) async {
var files = await directory.list().toList(); var files = await directory.list().toList();
var filesToWrite = <Future>{}; var filesToWrite = <Future<void>>{};
for (var entity in files) { for (final entity in files) {
var extension = path.extension(entity.path); var extension = path.extension(entity.path);
var filename = path.basenameWithoutExtension(entity.path); var filename = path.basenameWithoutExtension(entity.path);
if (extension != '.png' || entity is! File || filename.endsWith('_thumb')) { if (extension != '.png' || entity is! File || filename.endsWith('_thumb')) {
@ -117,8 +117,8 @@ Future<void> _createThumbnails(Directory directory) async {
@Task('remove generated HTML files') @Task('remove generated HTML files')
Future<void> clean() async { Future<void> clean() async {
var tasks = <Future>[]; var tasks = <Future<void>>[];
await for (var file in Directory('web').list(recursive: true)) { await for (final file in Directory('web').list(recursive: true)) {
if (path.extension(file.path) == '.html') { if (path.extension(file.path) == '.html') {
tasks.add(file.delete()); tasks.add(file.delete());
} }

@ -137,7 +137,7 @@ void filterCards() {
// Filter out all elements with non-matching search-attrs // Filter out all elements with non-matching search-attrs
var elements = querySelectorAll('[search-attrs]'); var elements = querySelectorAll('[search-attrs]');
for (var element in elements) { for (final element in elements) {
var searchAttributes = element.attributes['search-attrs']; var searchAttributes = element.attributes['search-attrs'];
if (matchesQuery(searchQuery, searchAttributes!)) { if (matchesQuery(searchQuery, searchAttributes!)) {
element.hidden = false; element.hidden = false;

@ -423,7 +423,7 @@ a {
margin-right: 8px; margin-right: 8px;
&:last-child { &:last-child {
margin-right: 0px; margin-right: 0;
} }
height: 8px; height: 8px;

Loading…
Cancel
Save