mirror of
https://github.com/flutter/samples.git
synced 2026-03-25 13:51:35 +00:00
Add samples index (#359)
* add samples_index to web/ directory Co-authored-by: Thea Flowers <theaflowers@google.com> * add pub_get.dart script * build sample index in peanut post build * re-generate sample index with web demos * print more details in peanut_post_build.dart * add images for demos * run generator * update README * add animations and provider shopper as symlinks * add links to symlinked web demos * use relative paths * update cookbook images, urls, and description CSS * use relative URL for navbar link * unstage HTML files * .gitignore generated HTML files * add margin to toolbar * rename escape functions * add and update copyright headers Co-authored-by: Thea Flowers <theaflowers@google.com>
This commit is contained in:
38
web/_tool/common.dart
Normal file
38
web/_tool/common.dart
Normal file
@@ -0,0 +1,38 @@
|
||||
// Copyright 2020 The Flutter team. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
const ansiGreen = 32;
|
||||
const ansiRed = 31;
|
||||
const ansiMagenta = 35;
|
||||
|
||||
Future<bool> run(
|
||||
String workingDir, String commandName, List<String> args) async {
|
||||
var commandDescription = '`${([commandName]..addAll(args)).join(' ')}`';
|
||||
|
||||
logWrapped(ansiMagenta, ' Running $commandDescription');
|
||||
|
||||
var proc = await Process.start(
|
||||
commandName,
|
||||
args,
|
||||
workingDirectory: Directory.current.path + '/' + workingDir,
|
||||
mode: ProcessStartMode.inheritStdio,
|
||||
);
|
||||
|
||||
var exitCode = await proc.exitCode;
|
||||
|
||||
if (exitCode != 0) {
|
||||
logWrapped(
|
||||
ansiRed, ' Failed! ($exitCode) – $workingDir – $commandDescription');
|
||||
return false;
|
||||
} else {
|
||||
logWrapped(ansiGreen, ' Success! – $workingDir – $commandDescription');
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void logWrapped(int code, String message) {
|
||||
print('\x1B[${code}m$message\x1B[0m');
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
// Copyright 2019 The Chromium Authors. All rights reserved.
|
||||
// Copyright 2020 The Flutter team. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
// found in the LICENSE file
|
||||
|
||||
// Called by https://pub.dartlang.org/packages/peanut to generate example pages
|
||||
// for hosting.
|
||||
@@ -10,10 +10,11 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:markdown/markdown.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
|
||||
void main(List<String> args) {
|
||||
import 'common.dart';
|
||||
|
||||
main(List<String> args) async {
|
||||
final buildDir = args[0];
|
||||
final fileMap =
|
||||
(jsonDecode(args[1]) as Map<String, dynamic>).cast<String, String>();
|
||||
@@ -32,21 +33,26 @@ void main(List<String> args) {
|
||||
}
|
||||
}
|
||||
|
||||
final tocFile = File(p.join(buildDir, 'index.html'));
|
||||
if (!tocFile.existsSync()) {
|
||||
throw StateError('$tocFile should exist!');
|
||||
// Move each sample into a subdirectory, 'web'
|
||||
for (var exampleDir in fileMap.values) {
|
||||
var oldDirectory = Directory(p.join(buildDir, exampleDir));
|
||||
Directory(p.join(buildDir, 'web')).createSync();
|
||||
oldDirectory.renameSync(p.join(buildDir, 'web', exampleDir));
|
||||
}
|
||||
|
||||
tocFile.writeAsStringSync(
|
||||
_tocTemplate(
|
||||
fileMap.entries.map(
|
||||
(entry) => _Demo(
|
||||
entry.key,
|
||||
entry.value,
|
||||
),
|
||||
),
|
||||
),
|
||||
flush: true);
|
||||
// Build the sample index and copy the files into this directory
|
||||
print('building the sample index...');
|
||||
await run('samples_index', 'pub', ['get']);
|
||||
await run('samples_index', 'pub', ['run', 'grinder', 'build-release']);
|
||||
|
||||
// Copy the contents of the samples_index/public directory to the build
|
||||
// directory
|
||||
logWrapped(ansiMagenta, ' Copying samples_index/public to build directory');
|
||||
var contents = Directory(p.join('samples_index', 'public')).listSync();
|
||||
for (var entity in contents) {
|
||||
var newPath = p.join(buildDir, p.basename(entity.path));
|
||||
entity.renameSync(newPath);
|
||||
}
|
||||
}
|
||||
|
||||
void _updateHtml(File htmlFile, String buildDir, String exampleDir) {
|
||||
@@ -71,55 +77,6 @@ void _updateHtml(File htmlFile, String buildDir, String exampleDir) {
|
||||
}
|
||||
}
|
||||
|
||||
class _Demo {
|
||||
final String pkgDir, buildDir;
|
||||
|
||||
_Demo(this.pkgDir, this.buildDir);
|
||||
|
||||
String get content {
|
||||
final path = p.normalize(p.join(pkgDir, '..', 'README.md'));
|
||||
|
||||
final readmeFile = File(path);
|
||||
|
||||
if (!readmeFile.existsSync()) {
|
||||
print(' $path – No readme!');
|
||||
return '';
|
||||
}
|
||||
|
||||
var readmeContent = readmeFile.readAsStringSync();
|
||||
|
||||
final tripleLineIndex = readmeContent.indexOf('\n\n\n');
|
||||
var secondDoubleIndex = readmeContent.indexOf('\n\n');
|
||||
|
||||
if (secondDoubleIndex >= 0) {
|
||||
secondDoubleIndex = readmeContent.indexOf('\n\n', secondDoubleIndex + 1);
|
||||
}
|
||||
|
||||
final endIndices =
|
||||
([tripleLineIndex, secondDoubleIndex].where((i) => i >= 0).toList()
|
||||
..sort());
|
||||
|
||||
final endIndex =
|
||||
endIndices.isEmpty ? readmeContent.length : endIndices.first;
|
||||
|
||||
return markdownToHtml(readmeContent.substring(0, endIndex - 1));
|
||||
}
|
||||
|
||||
String get name => _prettyName(buildDir);
|
||||
|
||||
String get html => '''
|
||||
<div>
|
||||
<a href='$buildDir'>
|
||||
<img src='${p.url.join(buildDir, 'assets/assets/preview.png')}' width="300" alt="$name">
|
||||
</a>
|
||||
<a class='demo-title' href='$buildDir'>$name</a>
|
||||
<div>
|
||||
${_indent(content, 2)}
|
||||
</div>
|
||||
</div>
|
||||
''';
|
||||
}
|
||||
|
||||
final _underscoreOrSlash = RegExp('_|/');
|
||||
|
||||
String _prettyName(String input) =>
|
||||
@@ -139,75 +96,9 @@ const _analytics = '''
|
||||
gtag('config', '$_analyticsId');
|
||||
</script>''';
|
||||
|
||||
String _indent(String content, int spaces) =>
|
||||
LineSplitter.split(content).join('\n' + ' ' * spaces);
|
||||
|
||||
const _itemsReplace = r'<!-- ITEMS -->';
|
||||
|
||||
const _emptyTitle = '<title></title>';
|
||||
|
||||
const _standardMeta = '''
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
$_emptyTitle''';
|
||||
|
||||
String _tocTemplate(Iterable<_Demo> items) => '''
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
${_indent(_analytics, 2)}
|
||||
$_standardMeta
|
||||
<meta name="generator" content="https://pub.dartlang.org/packages/peanut">
|
||||
<style>
|
||||
body {
|
||||
font-family: "Google Sans", "Roboto", sans-serif;
|
||||
text-align: center;
|
||||
}
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: #1389FD;
|
||||
}
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
#toc {
|
||||
text-align: left;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-self: center;
|
||||
margin: 0 auto;
|
||||
align-content: space-between;
|
||||
justify-content: center;
|
||||
}
|
||||
#toc > div {
|
||||
width: 300px;
|
||||
padding: 1rem;
|
||||
margin: 0.5rem;
|
||||
border: 1px solid rgba(0, 0, 0, 0.125);
|
||||
border-radius: 4px;
|
||||
}
|
||||
#toc > div img {
|
||||
display: block;
|
||||
margin: 0 auto 1rem;
|
||||
}
|
||||
.demo-title {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
#toc > div p {
|
||||
margin-top: 0.5rem;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h2><a href='https://flutter.dev/web'>Flutter for web</a> samples</h2>
|
||||
<a href='https://github.com/flutter/samples/tree/master/web'>Sample source code</a>
|
||||
<div id="toc">
|
||||
$_itemsReplace
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
'''
|
||||
.replaceFirst(
|
||||
_itemsReplace, _indent(items.map((d) => d.html).join('\n'), 4))
|
||||
.replaceFirst(_emptyTitle, '<title>Flutter for web samples</title>');
|
||||
|
||||
@@ -7,14 +7,14 @@ packages:
|
||||
name: args
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.5.2"
|
||||
version: "1.5.3"
|
||||
charcode:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: charcode
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.2"
|
||||
version: "1.1.3"
|
||||
markdown:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -30,4 +30,4 @@ packages:
|
||||
source: hosted
|
||||
version: "1.6.4"
|
||||
sdks:
|
||||
dart: ">=2.1.1 <3.0.0"
|
||||
dart: ">=2.3.0 <3.0.0"
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
// Copyright 2019 The Chromium Authors. All rights reserved.
|
||||
// Copyright 2020 The Flutter team. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
// found in the LICENSE file
|
||||
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'common.dart';
|
||||
|
||||
const _ansiGreen = 32;
|
||||
const _ansiRed = 31;
|
||||
@@ -20,14 +21,14 @@ void main() async {
|
||||
final results = <bool>[];
|
||||
for (var i = 0; i < packageDirs.length; i++) {
|
||||
final dir = packageDirs[i];
|
||||
_logWrapped(_ansiMagenta, '\n$dir (${i + 1} of ${packageDirs.length})');
|
||||
results.add(await _run(dir, 'flutter', [
|
||||
logWrapped(_ansiMagenta, '\n$dir (${i + 1} of ${packageDirs.length})');
|
||||
results.add(await run(dir, 'flutter', [
|
||||
'pub',
|
||||
'pub',
|
||||
'upgrade',
|
||||
'--no-precompile',
|
||||
]));
|
||||
results.add(await _run(
|
||||
results.add(await run(
|
||||
dir,
|
||||
'dartanalyzer',
|
||||
['--fatal-infos', '--fatal-warnings', '.'],
|
||||
@@ -45,45 +46,16 @@ void _printStatus(List<bool> results) {
|
||||
var success = (successCount == results.length);
|
||||
var pct = 100 * successCount / results.length;
|
||||
|
||||
_logWrapped(success ? _ansiGreen : _ansiRed,
|
||||
logWrapped(success ? _ansiGreen : _ansiRed,
|
||||
'$successCount of ${results.length} (${pct.toStringAsFixed(2)}%)');
|
||||
}
|
||||
|
||||
void _logWrapped(int code, String message) {
|
||||
print('\x1B[${code}m$message\x1B[0m');
|
||||
}
|
||||
|
||||
Future<bool> _run(
|
||||
String workingDir, String commandName, List<String> args) async {
|
||||
var commandDescription = '`${([commandName]..addAll(args)).join(' ')}`';
|
||||
|
||||
_logWrapped(_ansiMagenta, ' Running $commandDescription');
|
||||
|
||||
var proc = await Process.start(
|
||||
commandName,
|
||||
args,
|
||||
workingDirectory: Directory.current.path + '/' + workingDir,
|
||||
mode: ProcessStartMode.inheritStdio,
|
||||
);
|
||||
|
||||
var exitCode = await proc.exitCode;
|
||||
|
||||
if (exitCode != 0) {
|
||||
_logWrapped(
|
||||
_ansiRed, ' Failed! ($exitCode) – $workingDir – $commandDescription');
|
||||
return false;
|
||||
} else {
|
||||
_logWrapped(_ansiGreen, ' Success! – $workingDir – $commandDescription');
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Iterable<String> _listPackageDirs(Directory dir) sync* {
|
||||
if (File('${dir.path}/pubspec.yaml').existsSync()) {
|
||||
yield dir.path;
|
||||
} else {
|
||||
for (var subDir in dir
|
||||
.listSync(followLinks: false)
|
||||
.listSync(followLinks: true)
|
||||
.whereType<Directory>()
|
||||
.where((d) => !Uri.file(d.path).pathSegments.last.startsWith('.'))) {
|
||||
yield* _listPackageDirs(subDir);
|
||||
|
||||
Reference in New Issue
Block a user