diff --git a/plugins/devtools/CHANGELOG.md b/plugins/devtools/CHANGELOG.md new file mode 100644 index 0000000..607b2c2 --- /dev/null +++ b/plugins/devtools/CHANGELOG.md @@ -0,0 +1,197 @@ +# v1.5.4 +## 10/26/2021 + +1. [](#improved) + * Moved offline check to CLI flag [#70](https://github.com/getgrav/grav-plugin-devtools/issues/70) + * Updated footer copyrights for Pure Blank + +# v1.5.3 +## 06/16/2021 + +1. [](#bugfix) + * Fixes over-zealous regex that caused duplication in copy tasks [#69](https://github.com/getgrav/grav-plugin-devtools/issues/69) + +# v1.5.2 +## 05/19/2021 + +1. [](#new) + * Added basic TailwindCSS theme [#65](https://github.com/getgrav/grav-plugin-devtools/pull/65) +1. [](#improved) + * Fixed typo [#67](https://github.com/getgrav/grav-plugin-devtools/pull/67) + * Use canonical URLs [#58](https://github.com/getgrav/grav-plugin-devtools/pull/58) + * Replace `theme_config` with `config.theme` [#60](https://github.com/getgrav/grav-plugin-devtools/pull/60) +1. [](#bugfix) + * Fixed a bad path regarding composer install after plugin creation + +# v1.5.1 +## 03/17/2021 + +1. [](#improved) + * Clearer instructions for composer initialization [#62](https://github.com/getgrav/grav-plugin-devtools/pull/62) + * Comment out autoload subscription event by default now that Grav 1.7 is out [#62](https://github.com/getgrav/grav-plugin-devtools/pull/62) + +# v1.5.0 +## 02/18/2021 + +1. [](#new) + * Updated CLI commands for latest standards + * Pass phpstan level 8 tests +1. [](#improved) + * Add default configuration to an inherited theme's YAML file [getgrav/grav-premium-issues#50](https://github.com/getgrav/grav-premium-issues/issues/50) +1. [](#bugfix) + * Output cmd does not correctly show colors [#56](https://github.com/getgrav/grav-plugin-devtools/issues/56) + +# v1.4.2 +## 12/02/2020 + +1. [](#improved) + * User return typehints in plugin.php + * Add proper twig escapes into a new theme + +# v1.4.1 +## 05/20/2020 + +1. [](#improved) + * Make name key Composer 2.0 compatible [#48](https://github.com/getgrav/grav-plugin-devtools/pull/48) +1. [](#bugfix) + * Correct type for themes [#49](https://github.com/getgrav/grav-plugin-devtools/pull/49) + +# v1.4.0 +## 04/27/2020 + +1. [](#new) + * Added new required `slug:` and `type:` attributes to blueprints +1. [](#improved) + * Fixed plugin autoload + +# v1.3.1 +## 02/24/2020 + +1. [](#improved) + * Set `validation: loose` in plugin blueprints by default + * Add Grav 1.6 dependency to all new plugins and themes + +# v1.3.0 +## 02/13/2020 + +1. [](#improved) + * Added composer-based autoloader to the `new-plugin` command + +# v1.2.4 +## 11/06/2019 + +1. [](#improved) + * Added the ability to use devtools without an online connection to GPM +1. [](#bugfix) + * Regression fix for missing `theme_config` in pure-blank [#45](https://github.com/getgrav/grav-plugin-devtools/issues/45) + +# v1.2.3 +## 06/20/2019 + +1. [](#improved) + * pure-blank: Use new 'deferred' blocks for header + * pure-blank: Use `home_url` variable + * pure-blank: Improved `README.md.twig` + +# v1.2.2 +## 04/21/2019 + +1. [](#bugfix) + * Add Github username field to new-theme template [#39](https://github.com/getgrav/grav-plugin-devtools/pull/39) + +# v1.2.1 +## 08/04/2018 + +1. [](#bugfix) + * Fixed incorrect folder name as a result of renaming typo of `inheritence` to `inheritance` [#32](https://github.com/getgrav/grav-plugin-devtools/issues/32) + +# v1.2.0 +## 07/25/2018 + +1. [](#new) + * Internationalization for blank plugin component [#30](https://github.com/getgrav/grav-plugin-devtools/issues/30) +1. [](#improved) + * Added a new check for reserved PHP words [#7](https://github.com/getgrav/grav-plugin-devtools/issues/7) + * Improved regex for valid emails [#21](https://github.com/getgrav/grav-plugin-devtools/issues/21) +1. [](#bugfix) + * Fix broken renaming when doing a theme 'copy' + * Typos [#31](https://github.com/getgrav/grav-plugin-devtools/pull/31) + +# v1.1.1 +## 03/29/2018 + +1. [](#bugfix) + * Fixed theme inheritance bug [#25](https://github.com/getgrav/grav-plugin-devtools/pull/25) + +# v1.1.0 +## 03/29/2018 + +1. [](#new) + * Added new Theme `copy` option to create a new theme from another +1. [](#improved) + * Stop flushing GPM cache on each call to speed things up considerably! +1. [](#bugfix) + * Updated README.md [#23](https://github.com/getgrav/grav-plugin-devtools/pull/23) + * Properly extend Theme or Plugin [#24](https://github.com/getgrav/grav-plugin-devtools/pull/24) + +# v1.0.8 +## 10/02/2017 + +1. [](#bugfix) + inherited theme is after new theme [#9](https://github.com/getgrav/grav-plugin-devtools/issues/9) + +# v1.0.7 +## 10/02/2017 + +1. [](#bugfix) + * Various fixes for things that broke with the blueprint generation PR [#20](https://github.com/getgrav/grav-plugin-devtools/issues/20) + +# v1.0.6 +## 09/28/2017 + +1. [](#new) + * Added blueprint generation [#17](https://github.com/getgrav/grav-plugin-devtools/pull/17) +1. [](#improved) + * changed Pure CDN location [#19](https://github.com/getgrav/grav-plugin-devtools/pull/19) +1. [](#bugfix) + * Fixed readme referencing `githubid` [#13](https://github.com/getgrav/grav-plugin-devtools/pull/13) + +# v1.0.5 +## 02/26/2017 + +1. [](#improved) + * Added GitHub ID prompt [#5](https://github.com/getgrav/grav-plugin-devtools/pull/5) +1. [](#bugfix) + * Added missing closing html tag [#12](https://github.com/getgrav/grav-plugin-devtools/pull/12) + +# v1.0.4 +## 10/19/2016 + +1. [](#improved) + * More complete README.md + * Typo in Error template + +# v1.0.3 +## 09/16/2016 + +1. [](#bugfix) + * Removed `Theme` from theme's class causing events to not process - https://github.com/getgrav/grav/issues/1047 + * Typo in README.md + +# v1.0.2 +## 07/20/2016 + +1. [](#bugfix) + * Removed old `header.html.twig` + +# v1.0.1 +## 05/06/2016 + +1. [](#bugfix) + * Fix for Grav 1.0.x + +# v1.0.0 +## 04/19/2016 + +1. [](#new) + * ChangeLog started... diff --git a/plugins/devtools/LICENSE b/plugins/devtools/LICENSE new file mode 100644 index 0000000..4bb7092 --- /dev/null +++ b/plugins/devtools/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 Grav + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/plugins/devtools/README.md b/plugins/devtools/README.md new file mode 100644 index 0000000..c785a2b --- /dev/null +++ b/plugins/devtools/README.md @@ -0,0 +1,79 @@ +# Grav Devtools Plugin + +The `devtools` is a [Grav](http://github.com/getgrav/grav) Plugin that lets you quickly create a scaffolding for your new plugins and themes. The plugin provides CLI commands that allow for the quick and easy deployment of a sample scaffolding for your new plugin. + +# Installation + +## GPM Installation (Preferred) + +The simplest way to install this plugin is via the [Grav Package Manager (GPM)](http://learn.getgrav.org/advanced/grav-gpm). From the root of your Grav install type: + + bin/gpm install devtools + +## Manual Installation + +If for some reason you can't use GPM you can manually install this plugin. Download the zip version of this repository and unzip it under `/your/site/grav/user/plugins`. Then, rename the folder to `devtools`. + +You should now have all the plugin files under + + /your/site/grav/user/plugins/devtools + +## Configuration + +By default, devtools will perform a check with the online gpm repository to ensure name-collision avoidance. If you wish to not perform this online check, change the devtools.yaml at `user/config/plugins` from `collision_check: true` to `collision_check: false`. + +# Usage + +## Plugin Scaffolding + +To create a new plugin you simply need to run: `bin/plugin devtools new-plugin` and fill in the few questions at the prompts: + +``` +> bin/plugin devtools new-plugin +Enter Plugin Name: MyPlugin +Enter Plugin Description: My New Custom Plugin +Enter Developer Name: Johnny Rotten +Enter GitHub ID (can be blank): pretty-vacant +Enter Developer Email: johnny@rotten.com + +SUCCESS plugin myplugin -> Created Successfully + +Path: /home/johnnyr/webroot/grav-installation/user/plugins/myplugin +``` + +## Theme Scaffolding + +To create a new theme you simply need to run: `bin/plugin devtools new-theme` and fill in the few questions at the prompts: + +``` +> bin/plugin devtools new-theme +Enter Theme Name: MyTheme +Enter Theme Description: My New Custom Theme +Enter Developer Name: Johnny Rotten +Enter GitHub ID (can be blank): pretty-vacant +Enter Developer Email: johnny@rotten.com +Please choose a template type + [pure-blank ] Basic Theme using Pure.css + [inheritance] Inherit from another theme + [copy ] Copy another theme + > pure-blank + +SUCCESS theme mytheme -> Created Successfully + +Path: /home/johnnyr/webroot/grav-installation/user/themes/mytheme +``` + +There are **three template creation options** + +1. `pure-blank` - This is a very basic blank theme that uses the [Pure CSS framework](http://purecss.io/) +2. `inheritance` - This creates a very basic template with minimal files that inherits a base theme. To find out more about theme inheritance, [check out the subject in more details on the Grav Learn site](https://learn.getgrav.org/themes/customization#theme-inheritance). +3. `copy` - This allows you to create a new theme based on an existing theme. This is the simplest way to get started with a new theme by using another theme as the basis. + +## Skipping Online Project Name Collision Checking + +By default, devtools will check your project's name with the existing gpm ecosystem to ensure no collisions. In order to skip this check, add an `--offline` or `-o` to your command: + + `bin/plugin devtools new-theme --offline` +or + + `bin/plugin devtools new-theme -o` diff --git a/plugins/devtools/blueprints.yaml b/plugins/devtools/blueprints.yaml new file mode 100644 index 0000000..33f8c40 --- /dev/null +++ b/plugins/devtools/blueprints.yaml @@ -0,0 +1,41 @@ +name: DevTools +slug: devtools +type: plugin +version: 1.5.4 +description: Plugin and Theme scaffolding utilities +icon: cogs +author: + name: Team Grav + email: devs@getgrav.org + url: http://getgrav.org +homepage: https://github.com/getgrav/grav-plugin-devtools +keywords: devtools, plugin, theme +bugs: https://github.com/getgrav/grav-plugin-devtools/issues +license: MIT + +dependencies: + - { name: grav, version: '>=1.7.0' } + +form: + validation: strict + fields: + enabled: + type: toggle + label: PLUGIN_ADMIN.PLUGIN_STATUS + highlight: 1 + default: 0 + options: + 1: PLUGIN_ADMIN.ENABLED + 0: PLUGIN_ADMIN.DISABLED + validate: + type: bool + collision_check: + type: toggle + label: PLUGIN_DEVTOOLS.COLLISION_CHECK + highlight: 1 + default: 1 + options: + 1: PLUGIN_ADMIN.ENABLED + 0: PLUGIN_ADMIN.DISABLED + validate: + type: bool diff --git a/plugins/devtools/classes/DevToolsCommand.php b/plugins/devtools/classes/DevToolsCommand.php new file mode 100644 index 0000000..1271f06 --- /dev/null +++ b/plugins/devtools/classes/DevToolsCommand.php @@ -0,0 +1,362 @@ +init(); + $grav['uri']->init(); + + $this->inflector = $grav['inflector']; + $this->locator = $grav['locator']; + $this->twig = $grav['twig']; + $this->gpm = new GPM(); + + //Add `theme://` to prevent fail + $this->locator->addPath('theme', '', []); + $this->locator->addPath('plugin', '', []); + $this->locator->addPath('blueprint', '', []); + // $this->config->set('theme', $config->get('themes.' . $name)); + } + + /** + * Backwards compatibility to Grav 1.6. + * + * @return InputInterface + */ + public function getInput(): InputInterface + { + return $this->input; + } + + /** + * Backwards compatibility to Grav 1.6. + * + * @return SymfonyStyle + */ + public function getIO(): SymfonyStyle + { + $output = $this->output; + if (!$output instanceof SymfonyStyle) { + $this->output = $output = new SymfonyStyle($this->input, $this->output); + } + + return $this->output; + } + + /** + * Copies the component type and renames accordingly + * + * @return bool + */ + protected function createComponent(): bool + { + $name = $this->component['name']; + $folder_name = strtolower($this->inflector::hyphenize($name)); + $new_theme = $folder_name; + $type = $this->component['type']; + $grav = Grav::instance(); + $config = $grav['config']; + $current_theme = $config->get('system.pages.theme'); + $template = $this->component['template']; + $source_theme = null; + + if (isset($this->component['copy'])) { + $current_theme = $this->component['copy']; + $source_theme = $this->locator->findResource('themes://' . $current_theme); + $template_folder = $source_theme; + } else { + $template_folder = __DIR__ . "/../components/{$type}/{$template}"; + } + + if ($type === 'blueprint') { + $component_folder = $this->locator->findResource('themes://' . $current_theme) . '/blueprints'; + } else { + $component_folder = $this->locator->findResource($type . 's://') . DS . $folder_name; + } + + if (false === $template_folder) { + $this->output->writeln("Theme {$current_theme} does not exist"); + return false; + } + + if ($template === 'inheritance') { + $parent_theme = $this->component['extends']; + $yaml_file = $this->locator->findResource('themes://' . $parent_theme) . '/' . $parent_theme . '.yaml'; + $this->component['config'] = file_get_contents($yaml_file);; + } + + if (isset($source_theme)) { + /** + * Copy existing theme and regex-replace old stuff with new + */ + + // Get source if a symlink + if (is_link($template_folder)) { + $template_folder = readlink($template_folder); + if (false === $template_folder) { + $this->output->writeln("Theme {$current_theme} is a bad symlink"); + return false; + } + } + + //Copy All files to component folder + try { + Folder::copy($template_folder, $component_folder, '/.git|node_modules/'); + } catch (\Exception $e) { + $this->output->writeln("" . $e->getMessage() . ""); + return false; + } + + // Do some filename renaming + $base_old_filename = $component_folder . '/' . $current_theme; + $base_new_filename = $component_folder . '/' . $new_theme; + @rename( $base_old_filename . '.php', $base_new_filename . '.php'); + @rename( $base_old_filename . '.yaml', $base_new_filename . '.yaml'); + + $camelized_current = $this->inflector::camelize($current_theme); + $camelized_new = $this->inflector::camelize($name); + + $hyphenized_current = $this->inflector::hyphenize($current_theme); + $hyphenized_new = $this->inflector::hyphenize($name); + + $titleized_current = $this->inflector::titleize($current_theme); + $titleized_new = $this->inflector::titleize($name); + + $underscoreized_current = $this->inflector::underscorize($current_theme); + $underscoreized_new = $this->inflector::underscorize($name); + + $variations_regex = [ + ["/$camelized_current/", "/$hyphenized_current/"], + [$camelized_new, $hyphenized_new] + ]; + + if (!in_array("/$titleized_current/", array_values($variations_regex[0]))) { + $current_regex = $variations_regex[0]; + $new_regex = $variations_regex[1]; + $current_regex[] = "/$titleized_current/"; + $new_regex[] = $titleized_new; + $variations_regex = [$current_regex, $new_regex]; + } + + if (!in_array("/$underscoreized_current/", array_values($variations_regex[0]))) { + $current_regex = $variations_regex[0]; + $new_regex = $variations_regex[1]; + $current_regex[] = "/$underscoreized_current/"; + $new_regex[] = $underscoreized_new; + $variations_regex = [$current_regex, $new_regex]; + } + + $regex_array = [ + $new_theme . '.php' => $variations_regex, + 'blueprints.yaml' => $variations_regex, + 'README.md' => $variations_regex, + ]; + + foreach ($regex_array as $filename => $data) { + $filename = $component_folder . '/' . $filename; + if (!file_exists($filename)) { + continue; + } + $file = file_get_contents($filename); + if ($file) { + $file = preg_replace($data[0], $data[1], $file); + } + file_put_contents($filename, $file); + } + + echo $source_theme; + + } else { + /** + * Use components folder and twig processing + */ + //Copy All files to component folder + try { + Folder::copy($template_folder, $component_folder); + } catch (\Exception $e) { + $this->output->writeln("" . $e->getMessage() . ""); + return false; + } + + //Add Twig vars and templates then initialize + $this->twig->twig_vars['component'] = $this->component; + $this->twig->twig_paths[] = $template_folder; + $this->twig->init(); + + //Get all templates of component then process each with twig and save + $templates = Folder::all($component_folder); + + try { + foreach($templates as $templateFile) { + if (Utils::endsWith($templateFile, '.twig') && !Utils::endsWith($templateFile, '.html.twig')) { + $content = $this->twig->processTemplate($templateFile); + $file = File::instance($component_folder . DS . str_replace('.twig', '', $templateFile)); + $file->content($content); + $file->save(); + + //Delete twig template + $file = File::instance($component_folder . DS . $templateFile); + $file->delete(); + } + } + } catch (\Exception $e) { + $this->output->writeln("" . $e->getMessage() . ""); + $this->output->writeln("Rolling back..."); + Folder::delete($component_folder); + $this->output->writeln($type . "creation failed!"); + return false; + } + if ($type !== 'blueprint') { + rename($component_folder . DS . $type . '.php', $component_folder . DS . $folder_name . '.php'); + rename($component_folder . DS . $type . '.yaml', $component_folder . DS . $folder_name . '.yaml'); + } else { + $bpname = $this->inflector::hyphenize($this->component['bpname']); + rename($component_folder . DS . $type . '.yaml', $component_folder . DS . $bpname . '.yaml'); + } + } + + $this->output->writeln(''); + $this->output->writeln('SUCCESS ' . $type . ' ' . $name . ' -> Created Successfully'); + $this->output->writeln(''); + $this->output->writeln('Path: ' . $component_folder . ''); + $this->output->writeln(''); + if ($type === 'plugin') { + $this->output->writeln('Please run `cd ' . $component_folder . '` and `composer update` to initialize the autoloader'); + $this->output->writeln(''); + } + + return true; + } + + /** + * Iterate through all options and validate + * + * @return void + */ + protected function validateOptions(): void + { + foreach (array_filter($this->options) as $type => $value) { + $this->validate($type, $value); + } + } + + /** + * @param string $type + * @param mixed $value + * @return mixed + */ + protected function validate(string $type, $value) + { + switch ($type) { + case 'name': + // Check If name + if ($value === null || trim($value) === '') { + throw new \RuntimeException('Name cannot be empty'); + } + + if (!$this->options['offline']) { + // Check for name collision with online gpm. + if (false !== $this->gpm->findPackage($value)) { + throw new \RuntimeException('Package name exists in GPM'); + } + } else { + $this->output->writeln(''); + $this->output->writeln(' Warning: Please note that by skipping the online check, your project\'s plugin or theme name may conflict with an existing plugin or theme.'); + } + + // Check if it's reserved + if ($this->isReservedWord(strtolower($value))) { + throw new \RuntimeException("\"" . $value . "\" is a reserved word and cannot be used as the name"); + } + + break; + + case 'description': + if($value === null || trim($value) === '') { + throw new \RuntimeException('Description cannot be empty'); + } + + break; + case 'themename': + if($value === null || trim($value) === '') { + throw new \RuntimeException('Theme Name cannot be empty'); + } + + break; + case 'developer': + if ($value === null || trim($value) === '') { + throw new \RuntimeException('Developer\'s Name cannot be empty'); + } + + break; + + case 'githubid': + // GitHubID can be blank, so nothing here + break; + + case 'email': + if (!preg_match('/^(?!(?:(?:\x22?\x5C[\x00-\x7E]\x22?)|(?:\x22?[^\x5C\x22]\x22?)){255,})(?!(?:(?:\x22?\x5C[\x00-\x7E]\x22?)|(?:\x22?[^\x5C\x22]\x22?)){65,}@)(?:(?:[\x21\x23-\x27\x2A\x2B\x2D\x2F-\x39\x3D\x3F\x5E-\x7E]+)|(?:\x22(?:[\x01-\x08\x0B\x0C\x0E-\x1F\x21\x23-\x5B\x5D-\x7F]|(?:\x5C[\x00-\x7F]))*\x22))(?:\.(?:(?:[\x21\x23-\x27\x2A\x2B\x2D\x2F-\x39\x3D\x3F\x5E-\x7E]+)|(?:\x22(?:[\x01-\x08\x0B\x0C\x0E-\x1F\x21\x23-\x5B\x5D-\x7F]|(?:\x5C[\x00-\x7F]))*\x22)))*@(?:(?:(?!.*[^.]{64,})(?:(?:(?:xn--)?[a-z0-9]+(?:-[a-z0-9]+)*\.){1,126}){1,}(?:(?:[a-z][a-z0-9]*)|(?:(?:xn--)[a-z0-9]+))(?:-[a-z0-9]+)*)|(?:\[(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){7})|(?:(?!(?:.*[a-f0-9][:\]]){7,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?)))|(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){5}:)|(?:(?!(?:.*[a-f0-9]:){5,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3}:)?)))?(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))(?:\.(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))){3}))\]))$/iD', $value)) { + throw new \RuntimeException('Not a valid email address'); + } + + break; + } + + return $value; + } + + /** + * @param string $word + * @return bool + */ + public function isReservedWord(string $word): bool + { + return in_array($word, $this->reserved_keywords, true); + } +} diff --git a/plugins/devtools/cli/NewBlueprintCommand.php b/plugins/devtools/cli/NewBlueprintCommand.php new file mode 100644 index 0000000..f1dee47 --- /dev/null +++ b/plugins/devtools/cli/NewBlueprintCommand.php @@ -0,0 +1,88 @@ +setName('new-blueprint') + ->setAliases(['newblueprint','blueprint']) + ->addOption( + 'bpname', + null, + InputOption::VALUE_OPTIONAL, + 'The name of your new Grav theme' + ) + ->addOption( + 'name', + null, + InputOption::VALUE_OPTIONAL, + 'The name of your new Grav theme' + ) + ->addOption( + 'template', + null, + InputOption::VALUE_OPTIONAL, + 'The name/username of the developer' + ) + ->setDescription('Create a blueprint that extend the default.yaml blueprint files') + ->setHelp('The new-blueprint command creates a new blueprint file.'); + } + + /** + * @return int + */ + protected function serve(): int + { + $this->init(); + + $input = $this->getInput(); + $io = $this->getIO(); + + $this->component['type'] = 'blueprint'; + $this->component['template'] = 'modular'; + $this->component['version'] = '0.1.0'; + $this->component['themename'] = 'bonjour'; + + $this->options = [ + 'name' => $input->getOption('name'), + 'bpname' => $input->getOption('bpname'), + 'template' => $input->getOption('template'), + + ]; + + $this->validateOptions(); + + $this->component = array_replace($this->component, $this->options); + + if (!$this->options['template']) { + $question = new ChoiceQuestion('Please choose a template type', ['newtab', 'append']); + + $this->component['template'] = $io->askQuestion($question); + } + if (!$this->options['bpname']) { + $question = new Question('Enter Blueprint Name'); + + $this->component['bpname'] = $io->askQuestion($question); + } + + $this->createComponent(); + + return 0; + } +} diff --git a/plugins/devtools/cli/NewPluginCommand.php b/plugins/devtools/cli/NewPluginCommand.php new file mode 100644 index 0000000..f57ee23 --- /dev/null +++ b/plugins/devtools/cli/NewPluginCommand.php @@ -0,0 +1,146 @@ +setName('new-plugin') + ->setAliases(['newplugin']) + ->addOption( + 'name', + null, + InputOption::VALUE_OPTIONAL, + 'The name of your new Grav plugin' + ) + ->addOption( + 'desc', + null, + InputOption::VALUE_OPTIONAL, + 'A description of your new Grav plugin' + ) + ->addOption( + 'dev', + null, + InputOption::VALUE_OPTIONAL, + 'The name/username of the developer' + ) + ->addOption( + 'github', + null, + InputOption::VALUE_OPTIONAL, + 'The developer\'s GitHub ID' + ) + ->addOption( + 'email', + 'e', + InputOption::VALUE_OPTIONAL, + 'The developer\'s email' + ) + ->addOption( + 'offline', + 'o', + InputOption::VALUE_NONE, + 'Skip online name collision check' + ) + ->setDescription('Creates a new Grav plugin with the basic required files') + ->setHelp('The new-plugin command creates a new Grav instance and performs the creation of a plugin.'); + } + + /** + * @return int + */ + protected function serve(): int + { + $this->init(); + + $input = $this->getInput(); + $io = $this->getIO(); + + $this->component['type'] = 'plugin'; + $this->component['template'] = 'blank'; + $this->component['version'] = '0.1.0'; + + $this->options = [ + 'name' => $input->getOption('name'), + 'description' => $input->getOption('desc'), + 'author' => [ + 'name' => $input->getOption('dev'), + 'email' => $input->getOption('email'), + 'githubid' => $input->getOption('github') + ], + 'offline' => $input->getOption('offline'), + ]; + + $this->validateOptions(); + + $this->component = array_replace($this->component, $this->options); + + if (!$this->options['name']) { + $question = new Question('Enter Plugin Name'); + $question->setValidator(function ($value) { + return $this->validate('name', $value); + }); + + $this->component['name'] = $io->askQuestion($question); + } + + if (!$this->options['description']) { + $question = new Question('Enter Plugin Description'); + $question->setValidator(function ($value) { + return $this->validate('description', $value); + }); + + $this->component['description'] = $io->askQuestion($question); + } + + if (!$this->options['author']['name']) { + $question = new Question('Enter Developer Name'); + $question->setValidator(function ($value) { + return $this->validate('developer', $value); + }); + + $this->component['author']['name'] = $io->askQuestion($question); + } + + + if (!$this->options['author']['githubid']) { + $question = new Question('Enter GitHub ID (can be blank)'); + $question->setValidator(function ($value) { + return $this->validate('githubid', $value); + }); + + $this->component['author']['githubid'] = $io->askQuestion($question); + } + + if (!$this->options['author']['email']) { + $question = new Question('Enter Developer Email'); + $question->setValidator(function ($value) { + return $this->validate('email', $value); + }); + + $this->component['author']['email'] = $io->askQuestion($question); + } + + $this->component['template'] = 'blank'; + + $this->createComponent(); + + return 0; + } + +} diff --git a/plugins/devtools/cli/NewThemeCommand.php b/plugins/devtools/cli/NewThemeCommand.php new file mode 100644 index 0000000..fb479ef --- /dev/null +++ b/plugins/devtools/cli/NewThemeCommand.php @@ -0,0 +1,171 @@ +setName('new-theme') + ->setAliases(['newtheme']) + ->addOption( + 'name', + null, + InputOption::VALUE_OPTIONAL, + 'The name of your new Grav theme' + ) + ->addOption( + 'desc', + null, + InputOption::VALUE_OPTIONAL, + 'A description of your new Grav theme' + ) + ->addOption( + 'dev', + null, + InputOption::VALUE_OPTIONAL, + 'The name/username of the developer' + ) + ->addOption( + 'github', + null, + InputOption::VALUE_OPTIONAL, + 'The developer\'s GitHub ID' + ) + ->addOption( + 'email', + null, + InputOption::VALUE_OPTIONAL, + 'The developer\'s email' + ) + ->addOption( + 'offline', + 'o', + InputOption::VALUE_NONE, + 'Skip online name collision check' + ) + ->setDescription('Creates a new Grav theme with the basic required files') + ->setHelp('The new-theme command creates a new Grav instance and performs the creation of a theme.'); + } + + /** + * @return int + */ + protected function serve(): int + { + $this->init(); + + $input = $this->getInput(); + $io = $this->getIO(); + + $this->component['type'] = 'theme'; + $this->component['template'] = 'blank'; + $this->component['version'] = '0.1.0'; + + $this->options = [ + 'name' => $input->getOption('name'), + 'description' => $input->getOption('desc'), + 'author' => [ + 'name' => $input->getOption('dev'), + 'email' => $input->getOption('email'), + 'githubid' => $input->getOption('github'), + ], + 'offline' => $input->getOption('offline'), + ]; + + $this->validateOptions(); + + $this->component = array_replace($this->component, $this->options); + + if (!$this->options['name']) { + $question = new Question('Enter Theme Name'); + $question->setValidator(function ($value) { + return $this->validate('name', $value); + }); + + $this->component['name'] = $io->askQuestion($question); + } + + if (!$this->options['description']) { + $question = new Question('Enter Theme Description'); + $question->setValidator(function ($value) { + return $this->validate('description', $value); + }); + + $this->component['description'] = $io->askQuestion($question); + } + + if (!$this->options['author']['name']) { + $question = new Question('Enter Developer Name'); + $question->setValidator(function ($value) { + return $this->validate('developer', $value); + }); + + $this->component['author']['name'] = $io->askQuestion($question); + } + + if (!$this->options['author']['githubid']) { + $question = new Question('Enter GitHub ID (can be blank)'); + $question->setValidator(function ($value) { + return $this->validate('githubid', $value); + }); + + $this->component['author']['githubid'] = $io->askQuestion($question); + } + + if (!$this->options['author']['email']) { + $question = new Question('Enter Developer Email'); + $question->setValidator(function ($value) { + return $this->validate('email', $value); + }); + + $this->component['author']['email'] = $io->askQuestion($question); + } + + $question = new ChoiceQuestion( + 'Please choose an option', + ['pure-blank' => 'Basic Theme using Pure.css', 'tailwind' => 'Basic Theme using tailwind.css', 'inheritance' => 'Inherit from another theme', 'copy' => 'Copy another theme'] + ); + $this->component['template'] = $io->askQuestion($question); + + if ($this->component['template'] === 'inheritance') { + $themes = $this->gpm->getInstalledThemes(); + $installedThemes = []; + foreach ($themes as $key => $theme) { + $installedThemes[] = $key; + } + + $question = new ChoiceQuestion('Please choose a theme to extend', $installedThemes); + $this->component['extends'] = $io->askQuestion($question); + } elseif ($this->component['template'] === 'copy') { + $themes = $this->gpm->getInstalledThemes(); + $installedThemes = []; + foreach ($themes as $key => $theme) { + $installedThemes[] = $key; + } + + $question = new ChoiceQuestion( + 'Please choose a theme to copy', + $installedThemes + ); + $this->component['copy'] = $io->askQuestion($question); + } + $this->createComponent(); + + return 0; + } +} diff --git a/plugins/devtools/components/blueprint/append/blueprint.yaml.twig b/plugins/devtools/components/blueprint/append/blueprint.yaml.twig new file mode 100644 index 0000000..8db427f --- /dev/null +++ b/plugins/devtools/components/blueprint/append/blueprint.yaml.twig @@ -0,0 +1,21 @@ +title: {{ component.bpname }} +extends@: + type: default + context: blueprints://pages + +form: + fields: + tabs: + type: tabs + active: 1 + + fields: + content: + fields: + header.an_example_text_field: + type: text + label: Add a number + default: 5 + validate: + required: true + type: int \ No newline at end of file diff --git a/plugins/devtools/components/blueprint/newtab/blueprint.yaml.twig b/plugins/devtools/components/blueprint/newtab/blueprint.yaml.twig new file mode 100644 index 0000000..d110556 --- /dev/null +++ b/plugins/devtools/components/blueprint/newtab/blueprint.yaml.twig @@ -0,0 +1,15 @@ +title: Item +extends@: + type: default + context: blueprints://pages + +form: + fields: + tabs: + fields: + blog: + type: tab + title: {{ component.bpname }} + + fields: + header.mytextfield: \ No newline at end of file diff --git a/plugins/devtools/components/plugin/blank/CHANGELOG.md.twig b/plugins/devtools/components/plugin/blank/CHANGELOG.md.twig new file mode 100644 index 0000000..973fb27 --- /dev/null +++ b/plugins/devtools/components/plugin/blank/CHANGELOG.md.twig @@ -0,0 +1,5 @@ +# v0.1.0 +## {{ "now"|date("m/d/Y") }} + +1. [](#new) + * ChangeLog started... diff --git a/plugins/devtools/components/plugin/blank/LICENSE.twig b/plugins/devtools/components/plugin/blank/LICENSE.twig new file mode 100644 index 0000000..6f88097 --- /dev/null +++ b/plugins/devtools/components/plugin/blank/LICENSE.twig @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) {{ "now"|date("Y") }} {{ component.author.name }} + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/plugins/devtools/components/plugin/blank/README.md.twig b/plugins/devtools/components/plugin/blank/README.md.twig new file mode 100644 index 0000000..e9cae52 --- /dev/null +++ b/plugins/devtools/components/plugin/blank/README.md.twig @@ -0,0 +1,59 @@ +{% set component_title = (component.name|titleize) %} +{% set component_hyphenated = (component.name|hyphenize) %} +{% set developer_hyphenated = (component.author.githubid|hyphenize) %} +# {{ component_title }} Plugin + +**This README.md file should be modified to describe the features, installation, configuration, and general usage of the plugin.** + +The **{{ component_title }}** Plugin is an extension for [Grav CMS](http://github.com/getgrav/grav). {{ component.description }} + +## Installation + +Installing the {{ component_title }} plugin can be done in one of three ways: The GPM (Grav Package Manager) installation method lets you quickly install the plugin with a simple terminal command, the manual method lets you do so via a zip file, and the admin method lets you do so via the Admin Plugin. + +### GPM Installation (Preferred) + +To install the plugin via the [GPM](http://learn.getgrav.org/advanced/grav-gpm), through your system's terminal (also called the command line), navigate to the root of your Grav-installation, and enter: + + bin/gpm install {{ component_hyphenated }} + +This will install the {{ component_title }} plugin into your `/user/plugins`-directory within Grav. Its files can be found under `/your/site/grav/user/plugins/{{ component_hyphenated }}`. + +### Manual Installation + +To install the plugin manually, download the zip-version of this repository and unzip it under `/your/site/grav/user/plugins`. Then rename the folder to `{{ component_hyphenated }}`. You can find these files on [GitHub](https://github.com/{{ developer_hyphenated }}/grav-plugin-{{ component_hyphenated }}) or via [GetGrav.org](http://getgrav.org/downloads/plugins#extras). + +You should now have all the plugin files under + + /your/site/grav/user/plugins/{{ component_hyphenated }} + +> NOTE: This plugin is a modular component for Grav which may require other plugins to operate, please see its [blueprints.yaml-file on GitHub](https://github.com/{{ developer_hyphenated }}/grav-plugin-{{ component_hyphenated }}/blob/master/blueprints.yaml). + +### Admin Plugin + +If you use the Admin Plugin, you can install the plugin directly by browsing the `Plugins`-menu and clicking on the `Add` button. + +## Configuration + +Before configuring this plugin, you should copy the `user/plugins/{{ component_hyphenated }}/{{ component_hyphenated }}.yaml` to `user/config/plugins/{{ component_hyphenated }}.yaml` and only edit that copy. + +Here is the default configuration and an explanation of available options: + +```yaml +enabled: true +``` + +Note that if you use the Admin Plugin, a file with your configuration named {{component_hyphenated}}.yaml will be saved in the `user/config/plugins/`-folder once the configuration is saved in the Admin. + +## Usage + +**Describe how to use the plugin.** + +## Credits + +**Did you incorporate third-party code? Want to thank somebody?** + +## To Do + +- [ ] Future plans, if any + diff --git a/plugins/devtools/components/plugin/blank/blueprints.yaml.twig b/plugins/devtools/components/plugin/blank/blueprints.yaml.twig new file mode 100644 index 0000000..bd0defd --- /dev/null +++ b/plugins/devtools/components/plugin/blank/blueprints.yaml.twig @@ -0,0 +1,37 @@ +{% set githubid = component.author.githubid ?: component.author.name|hyphenize -%} +name: {{ component.name|titleize }} +slug: {{ component.name|hyphenize }} +type: plugin +version: 0.1.0 +description: {{ component.description }} +icon: plug +author: + name: {{ component.author.name }} + email: {{ component.author.email }} +homepage: https://github.com/{{ githubid }}/grav-plugin-{{ component.name|hyphenize }} +demo: http://demo.yoursite.com +keywords: grav, plugin, etc +bugs: https://github.com/{{ githubid }}/grav-plugin-{{ component.name|hyphenize }}/issues +docs: https://github.com/{{ githubid }}/grav-plugin-{{ component.name|hyphenize }}/blob/develop/README.md +license: MIT + +dependencies: + - { name: grav, version: '>=1.6.0' } + +form: + validation: loose + fields: + enabled: + type: toggle + label: PLUGIN_ADMIN.PLUGIN_STATUS + highlight: 1 + default: 0 + options: + 1: PLUGIN_ADMIN.ENABLED + 0: PLUGIN_ADMIN.DISABLED + validate: + type: bool + text_var: + type: text + label: PLUGIN_{{ component.name|underscorize|upper }}.TEXT_VARIABLE + help: PLUGIN_{{ component.name|underscorize|upper }}.TEXT_VARIABLE_HELP diff --git a/plugins/devtools/components/plugin/blank/classes/.gitkeep b/plugins/devtools/components/plugin/blank/classes/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/plugins/devtools/components/plugin/blank/composer.json.twig b/plugins/devtools/components/plugin/blank/composer.json.twig new file mode 100644 index 0000000..14cfe4f --- /dev/null +++ b/plugins/devtools/components/plugin/blank/composer.json.twig @@ -0,0 +1,30 @@ +{% set githubid = component.author.githubid ?: component.author.name|hyphenize -%} +{ + "name": "{{ githubid|lower }}/{{ component.name|hyphenize }}", + "type": "grav-plugin", + "description": "{{ component.description }}", + "keywords": ["plugin"], + "homepage": "https://github.com/{{ githubid }}/grav-plugin-{{ component.name|hyphenize }}", + "license": "MIT", + "authors": [ + { + "name": "{{ component.author.name }}", + "email": "{{ component.author.email }}", + "role": "Developer" + } + ], + "require": { + "php": ">=7.1.3" + }, + "autoload": { + "psr-4": { + "Grav\\Plugin\\{{ component.name|camelize }}\\": "classes/" + }, + "classmap": ["{{ component.name|hyphenize }}.php"] + }, + "config": { + "platform": { + "php": "7.1.3" + } + } +} diff --git a/plugins/devtools/components/plugin/blank/languages.yaml.twig b/plugins/devtools/components/plugin/blank/languages.yaml.twig new file mode 100644 index 0000000..855cd0e --- /dev/null +++ b/plugins/devtools/components/plugin/blank/languages.yaml.twig @@ -0,0 +1,4 @@ +en: + PLUGIN_{{ component.name|underscorize|upper }}: + TEXT_VARIABLE: Text Variable + TEXT_VARIABLE_HELP: Text to add to the top of a page diff --git a/plugins/devtools/components/plugin/blank/plugin.php.twig b/plugins/devtools/components/plugin/blank/plugin.php.twig new file mode 100644 index 0000000..0daecc4 --- /dev/null +++ b/plugins/devtools/components/plugin/blank/plugin.php.twig @@ -0,0 +1,59 @@ + [ + // Uncomment following line when plugin requires Grav < 1.7 + // ['autoload', 100000], + ['onPluginsInitialized', 0] + ] + ]; + } + + /** + * Composer autoload + * + * @return ClassLoader + */ + public function autoload(): ClassLoader + { + return require __DIR__ . '/vendor/autoload.php'; + } + + /** + * Initialize the plugin + */ + public function onPluginsInitialized(): void + { + // Don't proceed if we are in the admin plugin + if ($this->isAdmin()) { + return; + } + + // Enable the main events we are interested in + $this->enable([ + // Put your main events here + ]); + } +} diff --git a/plugins/devtools/components/plugin/blank/plugin.yaml.twig b/plugins/devtools/components/plugin/blank/plugin.yaml.twig new file mode 100644 index 0000000..55e2f2e --- /dev/null +++ b/plugins/devtools/components/plugin/blank/plugin.yaml.twig @@ -0,0 +1,2 @@ +enabled: true +text_var: Custom Text added by the **{{ component.name|titleize }}** plugin (disable plugin to remove) diff --git a/plugins/devtools/components/theme/inheritance/CHANGELOG.md.twig b/plugins/devtools/components/theme/inheritance/CHANGELOG.md.twig new file mode 100644 index 0000000..973fb27 --- /dev/null +++ b/plugins/devtools/components/theme/inheritance/CHANGELOG.md.twig @@ -0,0 +1,5 @@ +# v0.1.0 +## {{ "now"|date("m/d/Y") }} + +1. [](#new) + * ChangeLog started... diff --git a/plugins/devtools/components/theme/inheritance/LICENSE.twig b/plugins/devtools/components/theme/inheritance/LICENSE.twig new file mode 100644 index 0000000..6f88097 --- /dev/null +++ b/plugins/devtools/components/theme/inheritance/LICENSE.twig @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) {{ "now"|date("Y") }} {{ component.author.name }} + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/plugins/devtools/components/theme/inheritance/README.md.twig b/plugins/devtools/components/theme/inheritance/README.md.twig new file mode 100644 index 0000000..ee5c0b7 --- /dev/null +++ b/plugins/devtools/components/theme/inheritance/README.md.twig @@ -0,0 +1,7 @@ +# {{ component.name|titleize }} Theme + +The **{{ component.name|titleize }}** Theme is for [Grav CMS](http://github.com/getgrav/grav). This README.md file should be modified to describe the features, installation, configuration, and general usage of this theme. + +## Description + +{{ component.description }} diff --git a/plugins/devtools/components/theme/inheritance/blueprints.yaml.twig b/plugins/devtools/components/theme/inheritance/blueprints.yaml.twig new file mode 100644 index 0000000..91700a3 --- /dev/null +++ b/plugins/devtools/components/theme/inheritance/blueprints.yaml.twig @@ -0,0 +1,19 @@ +{% set githubid = component.author.githubid ?: component.author.name|hyphenize -%} +name: {{ component.name|titleize }} +slug: {{ component.name|hyphenize }} +type: theme +version: 0.1.0 +description: {{ component.description }} +icon: rebel +author: + name: {{ component.author.name }} + email: {{ component.author.email }} +homepage: https://github.com/{{ githubid }}/grav-theme-{{ component.name|hyphenize }} +demo: http://demo.yoursite.com +keywords: grav, theme, etc +bugs: https://github.com/{{ githubid }}/grav-theme-{{ component.name|hyphenize }}/issues +readme: https://github.com/{{ githubid }}/grav-theme-{{ component.name|hyphenize }}/blob/develop/README.md +license: MIT + +dependencies: + - { name: grav, version: '>=1.6.0' } diff --git a/plugins/devtools/components/theme/inheritance/css/.gitkeep b/plugins/devtools/components/theme/inheritance/css/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/plugins/devtools/components/theme/inheritance/js/.gitkeep b/plugins/devtools/components/theme/inheritance/js/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/plugins/devtools/components/theme/inheritance/screenshot.jpg b/plugins/devtools/components/theme/inheritance/screenshot.jpg new file mode 100644 index 0000000..5205ca5 Binary files /dev/null and b/plugins/devtools/components/theme/inheritance/screenshot.jpg differ diff --git a/plugins/devtools/components/theme/inheritance/templates/.gitkeep b/plugins/devtools/components/theme/inheritance/templates/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/plugins/devtools/components/theme/inheritance/theme.php.twig b/plugins/devtools/components/theme/inheritance/theme.php.twig new file mode 100644 index 0000000..c05016c --- /dev/null +++ b/plugins/devtools/components/theme/inheritance/theme.php.twig @@ -0,0 +1,9 @@ +=1.6.0' } + +form: + validation: loose + fields: + dropdown.enabled: + type: toggle + label: Dropdown in Menu + highlight: 1 + default: 1 + options: + 1: PLUGIN_ADMIN.ENABLED + 0: PLUGIN_ADMIN.DISABLED + validate: + type: bool diff --git a/plugins/devtools/components/theme/pure-blank/css/custom.css b/plugins/devtools/components/theme/pure-blank/css/custom.css new file mode 100644 index 0000000..e796328 --- /dev/null +++ b/plugins/devtools/components/theme/pure-blank/css/custom.css @@ -0,0 +1,175 @@ +/* Core Stuff */ +* { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +body { + font-size: 1rem; + line-height: 1.7; + color: #606d6e; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + color: #454B4D; +} + +a { + color: #1F8CD6; + text-decoration: none; +} + +a:hover { + color: #175E91; +} + +pre { + background: #F0F0F0; + margin: 1rem 0; + border-radius: 2px; +} + +blockquote { + border-left: 10px solid #eee; + margin: 0; + padding: 0 2rem; +} + +/* Utility Classes */ +.wrapper { + margin: 0 3rem; +} + +.padding { + padding: 3rem 1rem; +} + +.left { + float: left; +} + +.right { + float: right +} + +.text-center { + text-align: center; +} + +.text-right { + text-align: right; +} + +.text-left { + text-align: left; +} + +/* Content Styling */ +.header .padding { + padding: 1rem 0; +} + +.header { + background-color: #1F8DD6; + color: #eee; +} + +.header a { + color: #fff; +} + +.header .logo { + font-size: 1.7rem; + text-transform: uppercase; +} + +.footer { + background-color: #eee; +} + +/* Menu Settings */ +.main-nav ul { + text-align: center; + letter-spacing: -1em; + margin: 0; + padding: 0; +} + +.main-nav ul li { + display: inline-block; + letter-spacing: normal; +} + +.main-nav ul li a { + position: relative; + display: block; + line-height: 45px; + color: #fff; + padding: 0 20px; + white-space: nowrap; +} + +.main-nav > ul > li > a { + border-radius: 2px; +} + +/*Active dropdown nav item */ +.main-nav ul li:hover > a { + background-color: #175E91; +} + +/* Selected Dropdown nav item */ +.main-nav ul li.selected > a { + background-color: #fff; + color: #175E91; +} + +/* Dropdown CSS */ +.main-nav ul li {position: relative;} + +.main-nav ul li ul { + position: absolute; + background-color: #1F8DD6; + min-width: 100%; + text-align: left; + z-index: 999; + + display: none; +} +.main-nav ul li ul li { + display: block; +} + +/* Dropdown CSS */ +.main-nav ul li ul ul { + left: 100%; + top: 0; +} + +/* Active on Hover */ +.main-nav li:hover > ul { + display: block; +} + +/* Child Indicator */ +.main-nav .has-children > a { + padding-right: 30px; +} +.main-nav .has-children > a:after { + font-family: FontAwesome; + content: '\f107'; + position: absolute; + display: inline-block; + right: 8px; + top: 0; +} + +.main-nav .has-children .has-children > a:after { + content: '\f105'; +} diff --git a/plugins/devtools/components/theme/pure-blank/fonts/.gitkeep b/plugins/devtools/components/theme/pure-blank/fonts/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/plugins/devtools/components/theme/pure-blank/images/logo.png b/plugins/devtools/components/theme/pure-blank/images/logo.png new file mode 100644 index 0000000..64be1a9 Binary files /dev/null and b/plugins/devtools/components/theme/pure-blank/images/logo.png differ diff --git a/plugins/devtools/components/theme/pure-blank/js/.gitkeep b/plugins/devtools/components/theme/pure-blank/js/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/plugins/devtools/components/theme/pure-blank/screenshot.jpg b/plugins/devtools/components/theme/pure-blank/screenshot.jpg new file mode 100644 index 0000000..5205ca5 Binary files /dev/null and b/plugins/devtools/components/theme/pure-blank/screenshot.jpg differ diff --git a/plugins/devtools/components/theme/pure-blank/templates/default.html.twig b/plugins/devtools/components/theme/pure-blank/templates/default.html.twig new file mode 100644 index 0000000..1e97738 --- /dev/null +++ b/plugins/devtools/components/theme/pure-blank/templates/default.html.twig @@ -0,0 +1,5 @@ +{% extends 'partials/base.html.twig' %} + +{% block content %} + {{ page.content|raw }} +{% endblock %} diff --git a/plugins/devtools/components/theme/pure-blank/templates/error.html.twig b/plugins/devtools/components/theme/pure-blank/templates/error.html.twig new file mode 100644 index 0000000..c945464 --- /dev/null +++ b/plugins/devtools/components/theme/pure-blank/templates/error.html.twig @@ -0,0 +1,8 @@ +{% extends 'partials/base.html.twig' %} + +{% block content %} +
+

Error!

+ {{ page.content|raw }} +
+{% endblock %} diff --git a/plugins/devtools/components/theme/pure-blank/templates/partials/base.html.twig b/plugins/devtools/components/theme/pure-blank/templates/partials/base.html.twig new file mode 100644 index 0000000..c4e7e60 --- /dev/null +++ b/plugins/devtools/components/theme/pure-blank/templates/partials/base.html.twig @@ -0,0 +1,70 @@ + + + +{% block head %} + + {% if header.title %}{{ header.title|e }} | {% endif %}{{ site.title|e }} + + + + {% include 'partials/metadata.html.twig' %} + + + +{% endblock head %} + +{% block stylesheets %} + {% do assets.addCss('https://unpkg.com/purecss@1.0.0/build/pure-min.css', 100) %} + {% do assets.addCss('https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css', 99) %} + {% do assets.addCss('theme://css/custom.css', 98) %} +{% endblock %} + +{% block javascripts %} + {% do assets.addJs('jquery', 100) %} +{% endblock %} + +{% block assets deferred %} + {{ assets.css()|raw }} + {{ assets.js()|raw }} +{% endblock %} + + + +{% block header %} +
+
+ + {% block header_navigation %} + + {% endblock %} +
+
+{% endblock %} + +{% block body %} +
+
+ {% block content %}{% endblock %} +
+
+{% endblock %} + +{% block footer %} + +{% endblock %} + +{% block bottom %} + {{ assets.js('bottom')|raw }} +{% endblock %} + + + diff --git a/plugins/devtools/components/theme/pure-blank/templates/partials/navigation.html.twig b/plugins/devtools/components/theme/pure-blank/templates/partials/navigation.html.twig new file mode 100644 index 0000000..28df6aa --- /dev/null +++ b/plugins/devtools/components/theme/pure-blank/templates/partials/navigation.html.twig @@ -0,0 +1,47 @@ +{% macro loop(page) %} + {% for p in page.children.visible %} + {% set current_page = (p.active or p.activeChild) ? 'selected' : '' %} + {% if p.children.visible.count > 0 %} +
  • + + {% if p.header.icon %}{% endif %} + {{ p.menu|e }} + + +
  • + {% else %} +
  • + + {% if p.header.icon %}{% endif %} + {{ p.menu|e }} + +
  • + {% endif %} + {% endfor %} +{% endmacro %} + + diff --git a/plugins/devtools/components/theme/pure-blank/theme.php.twig b/plugins/devtools/components/theme/pure-blank/theme.php.twig new file mode 100644 index 0000000..332b164 --- /dev/null +++ b/plugins/devtools/components/theme/pure-blank/theme.php.twig @@ -0,0 +1,9 @@ +=1.6.0' } + +form: + validation: loose + fields: + dropdown.enabled: + type: toggle + label: Dropdown in Menu + highlight: 1 + default: 1 + options: + 1: PLUGIN_ADMIN.ENABLED + 0: PLUGIN_ADMIN.DISABLED + validate: + type: bool + production: + type: toggle + label: Production Mode + highlight: 1 + default: 1 + options: + 1: PLUGIN_ADMIN.ENABLED + 0: PLUGIN_ADMIN.DISABLED + validate: + type: bool diff --git a/plugins/devtools/components/theme/tailwind/css/site.css b/plugins/devtools/components/theme/tailwind/css/site.css new file mode 100644 index 0000000..f578962 --- /dev/null +++ b/plugins/devtools/components/theme/tailwind/css/site.css @@ -0,0 +1,5 @@ +/*@import 'yourcssfile.css';*/ + +@tailwind base; +@tailwind components; +@tailwind utilities; diff --git a/plugins/devtools/components/theme/tailwind/fonts/.gitkeep b/plugins/devtools/components/theme/tailwind/fonts/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/plugins/devtools/components/theme/tailwind/images/logo.png b/plugins/devtools/components/theme/tailwind/images/logo.png new file mode 100644 index 0000000..64be1a9 Binary files /dev/null and b/plugins/devtools/components/theme/tailwind/images/logo.png differ diff --git a/plugins/devtools/components/theme/tailwind/js/.gitkeep b/plugins/devtools/components/theme/tailwind/js/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/plugins/devtools/components/theme/tailwind/languages/en.yaml.twig b/plugins/devtools/components/theme/tailwind/languages/en.yaml.twig new file mode 100644 index 0000000..2b48ba2 --- /dev/null +++ b/plugins/devtools/components/theme/tailwind/languages/en.yaml.twig @@ -0,0 +1,2 @@ +THEME_{{ component.name|hyphenize|replace({'-': '_'})|upper }}: + ERROR: 'Error!' diff --git a/plugins/devtools/components/theme/tailwind/package.json.twig b/plugins/devtools/components/theme/tailwind/package.json.twig new file mode 100644 index 0000000..902fac2 --- /dev/null +++ b/plugins/devtools/components/theme/tailwind/package.json.twig @@ -0,0 +1,30 @@ +{ + "name": "{{ component.name }}", + "repository": "", + "private": true, + "version": "0.1.0", + "description": "", + "main": "index.js", + "scripts": { + "build": "postcss css/site.css -o dist/css/site.css --verbose", + "watch": "postcss css/site.css -o dist/css/site.css --watch --verbose", + "prod" : "postcss css/site.css -o dist/css/site.min.css --env production --verbose" + }, + "dependencies": {}, + "devDependencies": { + "alpinejs": "^2.8.2", + "tailwindcss": "^2.1.2", + "@tailwindcss/forms": "^0.3.2", + "@tailwindcss/typography": "^0.4.0", + "tailwindcss-debug-screens": "^2.0.0", + "autoprefixer": "^10.2.5", + "precss": "^4.0.0", + "cssnano": "^4.1.11", + "postcss": "^8.2.9", + "postcss-cli": "^8.3.1", + "postcss-import": "^14.0.1", + "postcss-nested": "^5.0.5", + "postcss-hexrgba": "^2.0.1", + "postcss-color-function": "^4.1.0" + } +} diff --git a/plugins/devtools/components/theme/tailwind/postcss.config.js b/plugins/devtools/components/theme/tailwind/postcss.config.js new file mode 100644 index 0000000..655e577 --- /dev/null +++ b/plugins/devtools/components/theme/tailwind/postcss.config.js @@ -0,0 +1,11 @@ +module.exports = { + plugins: { + 'postcss-import': {}, + 'precss': {}, + 'tailwindcss': {}, + 'postcss-nested': {}, + 'autoprefixer': {}, + ...process.env.NODE_ENV === 'production' + ? {'cssnano': {}} : {} + }, +} diff --git a/plugins/devtools/components/theme/tailwind/screenshot.jpg b/plugins/devtools/components/theme/tailwind/screenshot.jpg new file mode 100644 index 0000000..5205ca5 Binary files /dev/null and b/plugins/devtools/components/theme/tailwind/screenshot.jpg differ diff --git a/plugins/devtools/components/theme/tailwind/tailwind.config.js.twig b/plugins/devtools/components/theme/tailwind/tailwind.config.js.twig new file mode 100644 index 0000000..27a4484 --- /dev/null +++ b/plugins/devtools/components/theme/tailwind/tailwind.config.js.twig @@ -0,0 +1,70 @@ +const { colors } = require('tailwindcss/defaultTheme'); + +module.exports = { + purge: [ + '../../config/**/*.yaml', + '../../pages/**/*.md', + './blueprints/**/*.yaml', + './js/**/*.js', + './templates/**/*.twig', + './{{ component.name|hyphenize }}.yaml', + './{{ component.name|hyphenize }}.php' + ], + darkMode: 'class', //false or 'media' or 'class' + theme: { + extend: { + screens: { + sm: '640px', + md: '768px', + lg: '1024px', + xl: '1280px', + '2xl': '1536px' + } + }, + colors: { + 'primary': { + 'lighter': colors.yellow['300'], + DEFAULT: colors.yellow['400'], + 'darker' : colors.yellow['500'], + }, + black: colors.black, + white: colors.white, + red: colors.red, + green: colors.green, + blue: colors.blue, + orange: colors.orange, + indigo: colors.indigo, + transparent: 'transparent', + 'inherit': 'inherit', + }, + typography: (theme) => ({ + DEFAULT: { + css: { + color: 'inherit', + lineHeight: 'inherit', + maxWidth: 'inherit', + a: { + transition: 'all 500ms', + color: theme('colors.primary.DEFAULT'), + '&:hover': { + color: theme('colors.primary.darker') + }, + textDecoration: 'none' + }, + strong: { + color: 'inherit' + }, + } + } + }), + }, + variants: { + extend: {}, + }, + plugins: [ + require('@tailwindcss/typography'), + require('@tailwindcss/forms'), + require('tailwindcss-debug-screens'), + ], + important: false, +} diff --git a/plugins/devtools/components/theme/tailwind/templates/default.html.twig b/plugins/devtools/components/theme/tailwind/templates/default.html.twig new file mode 100644 index 0000000..1e97738 --- /dev/null +++ b/plugins/devtools/components/theme/tailwind/templates/default.html.twig @@ -0,0 +1,5 @@ +{% extends 'partials/base.html.twig' %} + +{% block content %} + {{ page.content|raw }} +{% endblock %} diff --git a/plugins/devtools/components/theme/tailwind/templates/error.html.twig b/plugins/devtools/components/theme/tailwind/templates/error.html.twig new file mode 100644 index 0000000..c25efaa --- /dev/null +++ b/plugins/devtools/components/theme/tailwind/templates/error.html.twig @@ -0,0 +1,8 @@ +{% extends 'partials/base.html.twig' %} + +{% block content %} +
    +

    {{ 'THEME_TAILWIND.ERROR'|t }}

    + {{ page.content|raw }} +
    +{% endblock %} diff --git a/plugins/devtools/components/theme/tailwind/templates/partials/base.html.twig b/plugins/devtools/components/theme/tailwind/templates/partials/base.html.twig new file mode 100644 index 0000000..04509fd --- /dev/null +++ b/plugins/devtools/components/theme/tailwind/templates/partials/base.html.twig @@ -0,0 +1,67 @@ +{% set extension = config.theme.production ? '.min' : '' %} + + + + {% block head %} + + {% if header.title %}{{ header.title|e }} | {% endif %}{{ site.title|e }} + + + + {% include 'partials/metadata.html.twig' %} + + + + {% endblock head %} + + {% block stylesheets %} + {% do assets.addCss('theme://dist/css/app' ~ extension ~ '.css', 98) %} + {% endblock %} + + {% block javascripts %} + {% endblock %} + + {% block assets deferred %} + {{ assets.css()|raw }} + {{ assets.js()|raw }} + {% endblock %} + + + +{% block header %} +
    +
    + + {% block header_navigation %} + + {% endblock %} +
    +
    +{% endblock %} + +{% block body %} +
    +
    + {% block content %}{% endblock %} +
    +
    +{% endblock %} + +{% block footer %} + +{% endblock %} + +{% block bottom %} + {{ assets.js('bottom')|raw }} +{% endblock %} + + + diff --git a/plugins/devtools/components/theme/tailwind/templates/partials/navigation.html.twig b/plugins/devtools/components/theme/tailwind/templates/partials/navigation.html.twig new file mode 100644 index 0000000..28df6aa --- /dev/null +++ b/plugins/devtools/components/theme/tailwind/templates/partials/navigation.html.twig @@ -0,0 +1,47 @@ +{% macro loop(page) %} + {% for p in page.children.visible %} + {% set current_page = (p.active or p.activeChild) ? 'selected' : '' %} + {% if p.children.visible.count > 0 %} +
  • + + {% if p.header.icon %}{% endif %} + {{ p.menu|e }} + + +
  • + {% else %} +
  • + + {% if p.header.icon %}{% endif %} + {{ p.menu|e }} + +
  • + {% endif %} + {% endfor %} +{% endmacro %} + + diff --git a/plugins/devtools/components/theme/tailwind/theme.php.twig b/plugins/devtools/components/theme/tailwind/theme.php.twig new file mode 100644 index 0000000..332b164 --- /dev/null +++ b/plugins/devtools/components/theme/tailwind/theme.php.twig @@ -0,0 +1,9 @@ +