diff --git a/packages/static_shock_cli/lib/src/commands/create_command.dart b/packages/static_shock_cli/lib/src/commands/create_command.dart index e21c630..85001cf 100644 --- a/packages/static_shock_cli/lib/src/commands/create_command.dart +++ b/packages/static_shock_cli/lib/src/commands/create_command.dart @@ -6,6 +6,7 @@ import 'package:static_shock_cli/src/project_maintenance/build_project.dart'; import 'package:static_shock_cli/src/templates/blog_template.dart'; import 'package:static_shock_cli/src/templates/docs_multi_page_template.dart'; import 'package:static_shock_cli/src/templates/empty_template.dart'; +import 'package:static_shock_cli/src/templates/tailwind_template.dart'; import 'package:static_shock_cli/src/version_check.dart'; /// CLI [Command] that generates a new Static Shock project based on user preferences. @@ -16,6 +17,7 @@ class CreateCommand extends Command with PubVersionCheck { // TODO: create single-page docs template // _TemplateType.docsSinglePage: "Documentation (single page)", _TemplateType.empty: "Empty", + _TemplateType.tailwind: "Tailwind CSS", }; CreateCommand(this.log); @@ -27,7 +29,8 @@ class CreateCommand extends Command with PubVersionCheck { final name = "create"; @override - final description = "Creates a new static site project at the desired location."; + final description = + "Creates a new static site project at the desired location."; @override bool get takesArguments => true; @@ -36,9 +39,11 @@ class CreateCommand extends Command with PubVersionCheck { Future run() async { await super.run(); - log.info("Welcome to Static Shock! Let's get you started with a new project!"); + log.info( + "Welcome to Static Shock! Let's get you started with a new project!"); log.info(""); - log.info("We'll ask you a series of questions, and then we'll generate a custom website project just for you."); + log.info( + "We'll ask you a series of questions, and then we'll generate a custom website project just for you."); log.info(""); final templateType = log.chooseOne( @@ -50,7 +55,8 @@ class CreateCommand extends Command with PubVersionCheck { log.info("You chose: ${_templateNamesById[templateType]}."); log.info(""); - log.info("We'll ask you a series of questions to configure the template for your specific needs..."); + log.info( + "We'll ask you a series of questions to configure the template for your specific needs..."); log.info(""); late final Directory targetDirectory; @@ -63,10 +69,13 @@ class CreateCommand extends Command with PubVersionCheck { targetDirectory = await runMultiPageDocsTemplateWizard(log); case _TemplateType.empty: targetDirectory = await runEmptyTemplateWizard(log); + case _TemplateType.tailwind: + targetDirectory = await runTailwindTemplateWizard(log); } log.success("Your new Static Shock website has been generated!\n"); - final shouldInitialize = log.confirm("Would you like to immediately run a build of your new website?"); + final shouldInitialize = log.confirm( + "Would you like to immediately run a build of your new website?"); log.info(""); log.info("--------------------------------------"); @@ -78,7 +87,8 @@ class CreateCommand extends Command with PubVersionCheck { log.info(""); log.success("Congratulations, your new Static Shock website is ready!"); - log.detail("To learn how to further configure your website, please check our guides at https://staticshock.io"); + log.detail( + "To learn how to further configure your website, please check our guides at https://staticshock.io"); } } @@ -88,4 +98,5 @@ enum _TemplateType { // docsSinglePage, docsMultiPage, empty, + tailwind, } diff --git a/packages/static_shock_cli/lib/src/templates/tailwind_template.dart b/packages/static_shock_cli/lib/src/templates/tailwind_template.dart new file mode 100644 index 0000000..f202ecf --- /dev/null +++ b/packages/static_shock_cli/lib/src/templates/tailwind_template.dart @@ -0,0 +1,152 @@ +import 'dart:io'; +import 'dart:isolate'; + +import 'package:args/command_runner.dart'; +import 'package:mason/mason.dart'; +import 'package:static_shock_cli/src/project_maintenance/build_project.dart'; +import 'package:static_shock_cli/src/templates/basic_template_cli.dart'; + +/// Walks the user through a selection of details that are required to generate +/// and then generates the project. +Future runTailwindTemplateWizard(Logger log) async { + final configuration = BasicTemplateConfigurator.promptForConfiguration(log); + final targetDirectory = + BasicTemplateConfigurator.promptForOutputDirectory(log); + + await generateTailwindTemplate( + targetDirectory, + projectName: configuration.projectName, + projectDescription: configuration.projectDescription, + ); + + return targetDirectory; +} + +/// A CLI command that can be directly run with provided arguments, to generate +/// a new Static Shock project with a minimal collection of files. +class TailwindTemplateCommand extends Command { + static const argProjectName = "project-name"; + static const argProjectDescription = "project-description"; + static const argAutoInitialize = "auto-initialize"; + + TailwindTemplateCommand(this.log) { + argParser + ..addOption( + argProjectName, + help: + "The name of the new Static Shock project - it should be a valid Dart package name.", + mandatory: true, + ) + ..addOption( + argProjectDescription, + help: + "The description of the new Static Shock project - will be added to the project's pubspec file.", + defaultsTo: "", + ) + ..addFlag( + argAutoInitialize, + help: + "True if this command should immediately run 'dart pub get' and 'shock build' after generating the project.", + defaultsTo: true, + ); + } + + final Logger log; + + @override + String get name => "tailwind"; + + @override + String get description => + "Generate a new, Static Shock project with TailwindCSS pre-configured."; + + @override + Future run() async { + if (!argResults!.wasParsed(argProjectName)) { + log.err("Argument $argProjectName is required."); + printUsage(); + return; + } + final projectName = argResults![argProjectName] as String; + final projectDescription = argResults![argProjectDescription] as String; + + final targetPath = argResults!.rest.lastOrNull; + final targetDirectory = + targetPath != null ? Directory(targetPath) : Directory.current; + if (!targetDirectory.existsSync()) { + try { + targetDirectory.createSync(recursive: true); + } catch (exception) { + log.err( + "Failed to create project directory: ${targetDirectory.absolute}"); + log.err("$exception"); + return; + } + } + + await generateTailwindTemplate( + targetDirectory, + projectName: projectName, + projectDescription: projectDescription, + ); + + log.success("Successfully created a new Static Shock project!\n"); + + if (argResults![argAutoInitialize]) { + // Run "shock build". + await Project.build(log: log, workingDirectory: targetDirectory); + + // Run "pub get". + await Project.pubGet(log: log, workingDirectory: targetDirectory); + } + + log.success("Congratulations, your Static Shock project is ready to go!"); + log.info("\nTo learn how to use Static Shock, check out staticshock.io\n"); + } +} + +/// Generates a new Static Shock project using the "tailwind" template, placing +/// the files in the given [targetDirectory]. +/// +/// The generated files are configured with the given properties. +Future generateTailwindTemplate( + Directory targetDirectory, { + required String projectName, + required String projectDescription, +}) async { + final bundle = await _loadTemplateBundle(); + final generator = await MasonGenerator.fromBundle(bundle); + final target = DirectoryGeneratorTarget(targetDirectory); + + await generator.generate(target, vars: { + _templateKeyProjectName: projectName, + _templateKeyProjectDescription: projectDescription, + }); +} + +Future _loadTemplateBundle() async { + // We expect to run as a globally activated Dart package. To access assets bundled + // with our package, we need to resolve a package path to a file system path, as + // shown below. + // + // Note: Dart automatically looks under "lib/" within a package. When reading the + // path below, mentally insert "/lib/" between the package name and the first sub-directory. + // + // Reference: https://stackoverflow.com/questions/72255508/how-to-get-the-file-path-to-an-asset-included-in-a-dart-package + // TODO: How to create a "tailwind.bundle" + final packageUri = + Uri.parse('package:static_shock_cli/templates/tailwind.bundle'); + final absoluteUri = await Isolate.resolvePackageUri(packageUri); + + final file = File.fromUri(absoluteUri!); + if (!file.existsSync()) { + throw Exception( + "Couldn't locate the Static Shock 'tailwind' template in the package assets. Looked in: '${file.path}'"); + } + + // Decode the file's bytes into a Mason bundle. Return it. + return await MasonBundle.fromUniversalBundle(file.readAsBytesSync()); +} + +const _templateKeyProjectName = "project_name"; +const _templateKeyProjectDescription = "project_description"; diff --git a/packages/static_shock_cli/lib/src/templates/template_command.dart b/packages/static_shock_cli/lib/src/templates/template_command.dart index f541e80..6e3384f 100644 --- a/packages/static_shock_cli/lib/src/templates/template_command.dart +++ b/packages/static_shock_cli/lib/src/templates/template_command.dart @@ -3,12 +3,14 @@ import 'package:mason/mason.dart'; import 'package:static_shock_cli/src/templates/blog_template.dart'; import 'package:static_shock_cli/src/templates/docs_multi_page_template.dart'; import 'package:static_shock_cli/src/templates/empty_template.dart'; +import 'package:static_shock_cli/src/templates/tailwind_template.dart'; class TemplateCommand extends Command { TemplateCommand(Logger log) { addSubcommand(EmptyTemplateCommand(log)); addSubcommand(BlogTemplateCommand(log)); addSubcommand(DocsMultiPageTemplateCommand(log)); + addSubcommand(TailwindTemplateCommand(log)); } @override diff --git a/template_sources/template_tailwind/.gitignore b/template_sources/template_tailwind/.gitignore new file mode 100644 index 0000000..a74d1f1 --- /dev/null +++ b/template_sources/template_tailwind/.gitignore @@ -0,0 +1,15 @@ +# Build output +/build + +# https://dart.dev/guides/libraries/private-files +# Created by `dart pub` +.dart_tool/ + +# Android Studio and IntelliJ IDEA +.idea + +.DS_Store + +# Avoid committing pubspec.lock for library packages; see +# https://dart.dev/guides/libraries/private-files#pubspeclock. +pubspec.lock \ No newline at end of file diff --git a/template_sources/template_tailwind/analysis_options.yaml b/template_sources/template_tailwind/analysis_options.yaml new file mode 100644 index 0000000..dee8927 --- /dev/null +++ b/template_sources/template_tailwind/analysis_options.yaml @@ -0,0 +1,30 @@ +# This file configures the static analysis results for your project (errors, +# warnings, and lints). +# +# This enables the 'recommended' set of lints from `package:lints`. +# This set helps identify many issues that may lead to problems when running +# or consuming Dart code, and enforces writing Dart using a single, idiomatic +# style and format. +# +# If you want a smaller set of lints you can change this to specify +# 'package:lints/core.yaml'. These are just the most critical lints +# (the recommended set includes the core lints). +# The core lints are also what is used by pub.dev for scoring packages. + +include: package:lints/recommended.yaml + +# Uncomment the following section to specify additional rules. + +# linter: +# rules: +# - camel_case_types + +# analyzer: +# exclude: +# - path/to/excluded/files/** + +# For more information about the core and recommended set of lints, see +# https://dart.dev/go/core-lints + +# For additional information about configuring this file, see +# https://dart.dev/guides/language/analysis-options diff --git a/template_sources/template_tailwind/bin/linux/tailwindcss b/template_sources/template_tailwind/bin/linux/tailwindcss new file mode 100755 index 0000000..2a9b951 Binary files /dev/null and b/template_sources/template_tailwind/bin/linux/tailwindcss differ diff --git a/template_sources/template_tailwind/bin/macos/tailwindcss b/template_sources/template_tailwind/bin/macos/tailwindcss new file mode 100755 index 0000000..8d7bad7 Binary files /dev/null and b/template_sources/template_tailwind/bin/macos/tailwindcss differ diff --git a/template_sources/template_tailwind/bin/main.dart b/template_sources/template_tailwind/bin/main.dart new file mode 100644 index 0000000..9b46577 --- /dev/null +++ b/template_sources/template_tailwind/bin/main.dart @@ -0,0 +1,40 @@ +import 'dart:io'; + +import 'package:static_shock/static_shock.dart'; + +Future main(List arguments) async { + var operatingSystem = Platform.operatingSystem; + String tailwindPath = switch (operatingSystem) { + "macos" => "./bin/macos/tailwindcss", + "linux" => "./bin/linux/tailwindcss", + "windows" => "./bin/windows/tailwindcss.exe", + _ => throw UnsupportedError( + "Unsupported operating system: $operatingSystem", + ), + }; + + // Configure the static website generator. + final staticShock = StaticShock() + // Here, you can directly hook into the StaticShock pipeline. For example, + // you can copy an "images" directory from the source set to build set: + ..pick(ExtensionPicker("html")) + ..pick(DirectoryPicker.parse("images")) + // All 3rd party behavior is added through plugins, even the behavior + // shipped with Static Shock. + ..plugin(const MarkdownPlugin()) + ..plugin(const JinjaPlugin()) + ..plugin(const PrettyUrlsPlugin()) + ..plugin(const RedirectsPlugin()) + ..plugin(const SassPlugin()) + ..plugin(DraftingPlugin( + showDrafts: arguments.contains("preview"), + )) + ..plugin(TailwindPlugin( + input: "source/styles/tailwind.css", + output: "build/styles/tailwind.css", + tailwindPath: tailwindPath, + )); + + // Generate the static website. + await staticShock.generateSite(); +} diff --git a/template_sources/template_tailwind/bin/windows/tailwindcss.exe b/template_sources/template_tailwind/bin/windows/tailwindcss.exe new file mode 100644 index 0000000..d00f403 Binary files /dev/null and b/template_sources/template_tailwind/bin/windows/tailwindcss.exe differ diff --git a/template_sources/template_tailwind/pubspec.yaml b/template_sources/template_tailwind/pubspec.yaml new file mode 100644 index 0000000..fc3d275 --- /dev/null +++ b/template_sources/template_tailwind/pubspec.yaml @@ -0,0 +1,14 @@ +name: shock_template_tailwind +description: +version: 1.0.0 +publish_to: none + +environment: + sdk: ^3.0.0 + +dependencies: + static_shock: any + +dev_dependencies: + lints: ^2.0.0 + test: ^1.21.0 diff --git a/template_sources/template_tailwind/source/images/favicon/android-chrome-192x192.png b/template_sources/template_tailwind/source/images/favicon/android-chrome-192x192.png new file mode 100644 index 0000000..626294d Binary files /dev/null and b/template_sources/template_tailwind/source/images/favicon/android-chrome-192x192.png differ diff --git a/template_sources/template_tailwind/source/images/favicon/android-chrome-512x512.png b/template_sources/template_tailwind/source/images/favicon/android-chrome-512x512.png new file mode 100644 index 0000000..560e5da Binary files /dev/null and b/template_sources/template_tailwind/source/images/favicon/android-chrome-512x512.png differ diff --git a/template_sources/template_tailwind/source/images/favicon/apple-touch-icon.png b/template_sources/template_tailwind/source/images/favicon/apple-touch-icon.png new file mode 100644 index 0000000..9bd1f25 Binary files /dev/null and b/template_sources/template_tailwind/source/images/favicon/apple-touch-icon.png differ diff --git a/template_sources/template_tailwind/source/images/favicon/browserconfig.xml b/template_sources/template_tailwind/source/images/favicon/browserconfig.xml new file mode 100644 index 0000000..1c27da0 --- /dev/null +++ b/template_sources/template_tailwind/source/images/favicon/browserconfig.xml @@ -0,0 +1,9 @@ + + + + + + #da532c + + + diff --git a/template_sources/template_tailwind/source/images/favicon/favicon-16x16.png b/template_sources/template_tailwind/source/images/favicon/favicon-16x16.png new file mode 100644 index 0000000..ce34110 Binary files /dev/null and b/template_sources/template_tailwind/source/images/favicon/favicon-16x16.png differ diff --git a/template_sources/template_tailwind/source/images/favicon/favicon-32x32.png b/template_sources/template_tailwind/source/images/favicon/favicon-32x32.png new file mode 100644 index 0000000..d2873b6 Binary files /dev/null and b/template_sources/template_tailwind/source/images/favicon/favicon-32x32.png differ diff --git a/template_sources/template_tailwind/source/images/favicon/favicon.ico b/template_sources/template_tailwind/source/images/favicon/favicon.ico new file mode 100644 index 0000000..f782fd9 Binary files /dev/null and b/template_sources/template_tailwind/source/images/favicon/favicon.ico differ diff --git a/template_sources/template_tailwind/source/images/favicon/mstile-150x150.png b/template_sources/template_tailwind/source/images/favicon/mstile-150x150.png new file mode 100644 index 0000000..2afdd06 Binary files /dev/null and b/template_sources/template_tailwind/source/images/favicon/mstile-150x150.png differ diff --git a/template_sources/template_tailwind/source/images/favicon/safari-pinned-tab.svg b/template_sources/template_tailwind/source/images/favicon/safari-pinned-tab.svg new file mode 100644 index 0000000..b16609a --- /dev/null +++ b/template_sources/template_tailwind/source/images/favicon/safari-pinned-tab.svg @@ -0,0 +1,18 @@ + + + + +Created by potrace 1.14, written by Peter Selinger 2001-2017 + + + + + diff --git a/template_sources/template_tailwind/source/images/favicon/site.webmanifest b/template_sources/template_tailwind/source/images/favicon/site.webmanifest new file mode 100644 index 0000000..abd3cfe --- /dev/null +++ b/template_sources/template_tailwind/source/images/favicon/site.webmanifest @@ -0,0 +1,19 @@ +{ + "name": "", + "short_name": "", + "icons": [ + { + "src": "/images/favicon/android-chrome-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "/images/favicon/android-chrome-512x512.png", + "sizes": "512x512", + "type": "image/png" + } + ], + "theme_color": "#ffffff", + "background_color": "#ffffff", + "display": "standalone" +} diff --git a/template_sources/template_tailwind/source/images/flutter-logo.png b/template_sources/template_tailwind/source/images/flutter-logo.png new file mode 100644 index 0000000..de9ce05 Binary files /dev/null and b/template_sources/template_tailwind/source/images/flutter-logo.png differ diff --git a/template_sources/template_tailwind/source/index.html b/template_sources/template_tailwind/source/index.html new file mode 100644 index 0000000..f853085 --- /dev/null +++ b/template_sources/template_tailwind/source/index.html @@ -0,0 +1,347 @@ + + + + + + My Tailwind Website + + + + + + + + + + + + + + + + + +
+ +
+
+
+
+
+ + + + + + + + + + + + +
+
+

+ Welcome to your first Tailwind project! +

+

+ The file you're looking at is the + source/index.html. If you used + shock serve + to view this page, try editing that file to see this page + automatically update with your changes. +

+
+
+
+
+
+
+
+ + + + + + +
+
+

+ Documentation +

+

+ Get familiar with Tailwind's utility-first approach and + start building awesome stuff. +

+ +
+
+
+
+
+
+ + + + +
+
+

+ Component Examples +

+

+ Browse pre-built components using Tailwind’s utility + classes. +

+ +
+
+
+
+
+
+ + + + +
+
+

+ Resources +

+

+ A collection of assets and resources to help supercharge + your Tailwind workflow. +

+ +
+
+
+
+
+
+ + + + +
+
+

+ Community +

+

+ Connect and learn from other Tailwind users in the + community. +

+ +
+
+
+
+
+
+
+
+
+ + diff --git a/template_sources/template_tailwind/source/styles/tailwind.css b/template_sources/template_tailwind/source/styles/tailwind.css new file mode 100644 index 0000000..b5c61c9 --- /dev/null +++ b/template_sources/template_tailwind/source/styles/tailwind.css @@ -0,0 +1,3 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; diff --git a/template_sources/template_tailwind/tailwind.config.js b/template_sources/template_tailwind/tailwind.config.js new file mode 100644 index 0000000..b68a118 --- /dev/null +++ b/template_sources/template_tailwind/tailwind.config.js @@ -0,0 +1,7 @@ +/** @type {import('tailwindcss').Config} */ +module.exports = { + theme: {}, + variants: {}, + plugins: [], + content: ["./source/**/*.jinja", "./source/**/*.html"], +};