From 845fc39a735df9e72cb5eb153de94b9eac6b9d57 Mon Sep 17 00:00:00 2001 From: awcodes Date: Thu, 1 Sep 2022 14:59:18 -0400 Subject: [PATCH] add asset handling and colors to configure.php --- .github/workflows/pint.yml | 27 ++ .php_cs.dist.php | 2 +- composer.json | 22 +- configure.php | 593 +++++++++++++++++++++++++------- package.json | 20 ++ pint.json | 11 + postcss.config.js | 6 + resources/css/plugin.css | 1 + resources/dist/.gitkeep | 0 resources/js/plugin.js | 0 resources/lang/en/.gitkeep | 0 src/SkeletonServiceProvider.php | 30 ++ tailwind.config.js | 21 ++ 13 files changed, 602 insertions(+), 131 deletions(-) create mode 100644 .github/workflows/pint.yml create mode 100644 package.json create mode 100644 pint.json create mode 100644 postcss.config.js create mode 100644 resources/css/plugin.css create mode 100644 resources/dist/.gitkeep create mode 100644 resources/js/plugin.js create mode 100644 resources/lang/en/.gitkeep create mode 100644 tailwind.config.js diff --git a/.github/workflows/pint.yml b/.github/workflows/pint.yml new file mode 100644 index 0000000..1258df6 --- /dev/null +++ b/.github/workflows/pint.yml @@ -0,0 +1,27 @@ +name: pint + +on: push + +jobs: + pint: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v2 + with: + ref: ${{ github.head_ref }} + - name: Set up Node + uses: actions/setup-node@v2 + - name: Install dependencies + run: | + composer install --no-interaction + npm ci + - name: Run Pint + run: composer pint + - name: Run Prettier + run: npm run prettier + - name: Commit changes + uses: stefanzweifel/git-auto-commit-action@v4 + with: + commit_message: > + chore: fix code style diff --git a/.php_cs.dist.php b/.php_cs.dist.php index 8d8a790..cc5a4b2 100644 --- a/.php_cs.dist.php +++ b/.php_cs.dist.php @@ -37,4 +37,4 @@ return (new PhpCsFixer\Config()) ], 'single_trait_insert_per_statement' => true, ]) - ->setFinder($finder); + ->setFinder($finder); \ No newline at end of file diff --git a/composer.json b/composer.json index b87a213..565b91f 100644 --- a/composer.json +++ b/composer.json @@ -22,11 +22,14 @@ "illuminate/contracts": "^9.0" }, "require-dev": { + "laravel/pint": "^1.0", "nunomaduro/collision": "^6.0", "nunomaduro/larastan": "^2.0.1", "orchestra/testbench": "^7.0", "pestphp/pest": "^1.21", "pestphp/pest-plugin-laravel": "^1.1", + "pestphp/pest-plugin-livewire": "^1.0", + "pestphp/pest-plugin-parallel": "^0.3", "phpstan/extension-installer": "^1.1", "phpstan/phpstan-deprecation-rules": "^1.0", "phpstan/phpstan-phpunit": "^1.0", @@ -45,12 +48,21 @@ } }, "scripts": { - "analyse": "vendor/bin/phpstan analyse", - "test": "vendor/bin/pest", - "test-coverage": "vendor/bin/pest coverage" + "pint": "pint", + "test:pest": "pest --parallel", + "test:phpstan": "phpstan analyse", + "test": [ + "@test:pest", + "@test:phpstan" + ] }, "config": { - "sort-packages": true + "sort-packages": true, + "allow-plugins": { + "composer/package-versions-deprecated": true, + "pestphp/pest-plugin": true, + "phpstan/extension-installer": true + } }, "extra": { "laravel": { @@ -64,4 +76,4 @@ }, "minimum-stability": "dev", "prefer-stable": true -} +} \ No newline at end of file diff --git a/configure.php b/configure.php index 0f6abbc..57236db 100644 --- a/configure.php +++ b/configure.php @@ -1,125 +1,6 @@ #!/usr/bin/env php $version) { - if (in_array($name, $names, true)) { - unset($data['require-dev'][$name]); - } - } - - file_put_contents(__DIR__.'/composer.json', json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)); -} - -function remove_composer_script($scriptName) { - $data = json_decode(file_get_contents(__DIR__.'/composer.json'), true); - - foreach($data['scripts'] as $name => $script) { - if ($scriptName === $name) { - unset($data['scripts'][$name]); - break; - } - } - - file_put_contents(__DIR__.'/composer.json', json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)); -} - -function remove_readme_paragraphs(string $file): void { - $contents = file_get_contents($file); - - file_put_contents( - $file, - preg_replace('/.*/s', '', $contents) ?: $contents - ); -} - -function safeUnlink(string $filename) { - if (file_exists($filename) && is_file($filename)) { - unlink($filename); - } -} - -function determineSeparator(string $path): string { - return str_replace('/', DIRECTORY_SEPARATOR, $path); -} - -function replaceForWindows(): array { - return preg_split('/\\r\\n|\\r|\\n/', run('dir /S /B * | findstr /v /i .git\ | findstr /v /i vendor | findstr /v /i '.basename(__FILE__).' | findstr /r /i /M /F:/ ":author :vendor :package VendorName skeleton vendor_name vendor_slug author@domain.com"')); -} - -function replaceForAllOtherOSes(): array { - return explode(PHP_EOL, run('grep -E -r -l -i ":author|:vendor|:package|VendorName|skeleton|vendor_name|vendor_slug|author@domain.com" --exclude-dir=vendor ./* ./.github/* | grep -v ' . basename(__FILE__))); -} - $gitName = run('git config user.name'); $authorName = ask('Author name', $gitName); @@ -149,6 +30,7 @@ $description = ask('Package description', "This is my package {$packageSlug}"); $usePhpStan = confirm('Enable PhpStan?', true); $usePhpCsFixer = confirm('Enable PhpCsFixer?', true); +$usePint = confirm('Enable Pint?', true); $useUpdateChangelogWorkflow = confirm('Use automatic changelog updater workflow?', true); writeln('------'); @@ -157,11 +39,12 @@ writeln("Vendor : {$vendorName} ({$vendorSlug})"); writeln("Package : {$packageSlug} <{$description}>"); writeln("Namespace : {$vendorNamespace}\\{$className}"); writeln("Class name : {$className}"); -writeln("---"); -writeln("Packages & Utilities"); -writeln("Use PhpCsFixer : " . ($usePhpCsFixer ? 'yes' : 'no')); -writeln("Use Larastan/PhpStan : " . ($usePhpStan ? 'yes' : 'no')); -writeln("Use Auto-Changelog : " . ($useUpdateChangelogWorkflow ? 'yes' : 'no')); +writeln('---'); +writeln('Packages & Utilities'); +writeln('Use PhpCsFixer : ' . ($usePhpCsFixer ? 'yes' : 'no')); +writeln('Use Larastan/PhpStan : ' . ($usePhpStan ? 'yes' : 'no')); +writeln('Use Pint : ' . ($usePint ? 'yes' : 'no')); +writeln('Use Auto-Changelog : ' . ($useUpdateChangelogWorkflow ? 'yes' : 'no')); writeln('------'); writeln('This script will replace the above values in all relevant files in the project directory.'); @@ -205,6 +88,17 @@ if (! $usePhpCsFixer) { safeUnlink(__DIR__ . '/.github/workflows/php-cs-fixer.yml'); } +if (! $usePint) { + safeUnlink(__DIR__ . '/pint.json'); + safeUnlink(__DIR__ . '/.github/workflows/pint.yml'); + + remove_composer_deps([ + 'laravel/pint', + ]); + + remove_composer_script(['pint']); +} + if (! $usePhpStan) { safeUnlink(__DIR__ . '/phpstan.neon.dist'); safeUnlink(__DIR__ . '/phpstan-baseline.neon'); @@ -217,7 +111,10 @@ if (! $usePhpStan) { 'nunomaduro/larastan', ]); - remove_composer_script('phpstan'); + remove_composer_script([ + 'test:phpstan', + '@test:phpstan', + ]); } if (! $useUpdateChangelogWorkflow) { @@ -227,3 +124,449 @@ if (! $useUpdateChangelogWorkflow) { confirm('Execute `composer install` and run tests?') && run('composer install && composer test'); confirm('Let this script delete itself?', true) && unlink(__FILE__); + +function ask(string $question, string $default = ''): string +{ + $consoleColor = new ConsoleColor(); + $def = $default ? $consoleColor->apply('yellow', " ({$default})") : null; + $answer = readline($consoleColor->apply('green', $question . $def . ': ')); + + if (! $answer) { + return $default; + } + + return $answer; +} + +function confirm(string $question, bool $default = false): bool +{ + $consoleColor = new ConsoleColor(); + + $answer = ask($question, ($default ? 'Y/n' : 'y/N')); + + if (! $answer) { + return $default; + } + + return strtolower($answer) === 'y'; +} + +function writeln(string $line): void +{ + echo $line . PHP_EOL; +} + +function run(string $command): string +{ + return trim(shell_exec($command)); +} + +function str_after(string $subject, string $search): string +{ + $pos = strrpos($subject, $search); + + if ($pos === false) { + return $subject; + } + + return substr($subject, $pos + strlen($search)); +} + +function slugify(string $subject): string +{ + return strtolower(trim(preg_replace('/[^A-Za-z0-9-]+/', '-', $subject), '-')); +} + +function title_case(string $subject): string +{ + return str_replace(' ', '', ucwords(str_replace(['-', '_'], ' ', $subject))); +} + +function replace_in_file(string $file, array $replacements): void +{ + $contents = file_get_contents($file); + + file_put_contents( + $file, + str_replace( + array_keys($replacements), + array_values($replacements), + $contents + ) + ); +} + +function remove_prefix(string $prefix, string $content): string +{ + if (str_starts_with($content, $prefix)) { + return substr($content, strlen($prefix)); + } + + return $content; +} + +function remove_composer_deps(array $names) +{ + $data = json_decode(file_get_contents(__DIR__ . '/composer.json'), true); + + foreach ($data['require-dev'] as $name => $version) { + if (in_array($name, $names, true)) { + unset($data['require-dev'][$name]); + } + } + + file_put_contents(__DIR__ . '/composer.json', json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)); +} + +function remove_composer_script(array $scriptNames) +{ + $data = json_decode(file_get_contents(__DIR__ . '/composer.json'), true); + + foreach ($data['scripts'] as $name => $script) { + if (is_array($script)) { + foreach ($script as $k => $s) { + if (in_array($s, $scriptNames)) { + unset($data['scripts'][$name][$k]); + + break; + } + } + } elseif (in_array($name, $scriptNames)) { + unset($data['scripts'][$name]); + + break; + } + } + + file_put_contents(__DIR__ . '/composer.json', json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)); +} + +function remove_readme_paragraphs(string $file): void +{ + $contents = file_get_contents($file); + + file_put_contents( + $file, + preg_replace('/.*/s', '', $contents) ?: $contents + ); +} + +function safeUnlink(string $filename) +{ + if (file_exists($filename) && is_file($filename)) { + unlink($filename); + } +} + +function determineSeparator(string $path): string +{ + return str_replace('/', DIRECTORY_SEPARATOR, $path); +} + +function replaceForWindows(): array +{ + return preg_split('/\\r\\n|\\r|\\n/', run('dir /S /B * | findstr /v /i .git\ | findstr /v /i vendor | findstr /v /i ' . basename(__FILE__) . ' | findstr /r /i /M /F:/ ":author :vendor :package VendorName skeleton vendor_name vendor_slug author@domain.com"')); +} + +function replaceForAllOtherOSes(): array +{ + return explode(PHP_EOL, run('grep -E -r -l -i ":author|:vendor|:package|VendorName|skeleton|vendor_name|vendor_slug|author@domain.com" --exclude-dir=vendor ./* ./.github/* | grep -v ' . basename(__FILE__))); +} + +class ConsoleColor +{ + const FOREGROUND = 38; + + const BACKGROUND = 48; + + const COLOR256_REGEXP = '~^(bg_)?color_([0-9]{1,3})$~'; + + const RESET_STYLE = 0; + + /** @var bool */ + private $isSupported; + + /** @var bool */ + private $forceStyle = false; + + /** @var array */ + private $styles = [ + 'none' => null, + 'bold' => '1', + 'dark' => '2', + 'italic' => '3', + 'underline' => '4', + 'blink' => '5', + 'reverse' => '7', + 'concealed' => '8', + + 'default' => '39', + 'black' => '30', + 'red' => '31', + 'green' => '32', + 'yellow' => '33', + 'blue' => '34', + 'magenta' => '35', + 'cyan' => '36', + 'light_gray' => '37', + + 'dark_gray' => '90', + 'light_red' => '91', + 'light_green' => '92', + 'light_yellow' => '93', + 'light_blue' => '94', + 'light_magenta' => '95', + 'light_cyan' => '96', + 'white' => '97', + + 'bg_default' => '49', + 'bg_black' => '40', + 'bg_red' => '41', + 'bg_green' => '42', + 'bg_yellow' => '43', + 'bg_blue' => '44', + 'bg_magenta' => '45', + 'bg_cyan' => '46', + 'bg_light_gray' => '47', + + 'bg_dark_gray' => '100', + 'bg_light_red' => '101', + 'bg_light_green' => '102', + 'bg_light_yellow' => '103', + 'bg_light_blue' => '104', + 'bg_light_magenta' => '105', + 'bg_light_cyan' => '106', + 'bg_white' => '107', + ]; + + /** @var array */ + private $themes = []; + + public function __construct() + { + $this->isSupported = $this->isSupported(); + } + + /** + * @param string|array $style + * @param string $text + * @return string + * + * @throws InvalidStyleException + * @throws \InvalidArgumentException + */ + public function apply($style, $text) + { + if (! $this->isStyleForced() && ! $this->isSupported()) { + return $text; + } + + if (is_string($style)) { + $style = [$style]; + } + if (! is_array($style)) { + throw new \InvalidArgumentException('Style must be string or array.'); + } + + $sequences = []; + + foreach ($style as $s) { + if (isset($this->themes[$s])) { + $sequences = array_merge($sequences, $this->themeSequence($s)); + } elseif ($this->isValidStyle($s)) { + $sequences[] = $this->styleSequence($s); + } else { + throw new InvalidStyleException($s); + } + } + + $sequences = array_filter($sequences, function ($val) { + return $val !== null; + }); + + if (empty($sequences)) { + return $text; + } + + return $this->escSequence(implode(';', $sequences)) . $text . $this->escSequence(self::RESET_STYLE); + } + + /** + * @param bool $forceStyle + */ + public function setForceStyle($forceStyle) + { + $this->forceStyle = (bool) $forceStyle; + } + + /** + * @return bool + */ + public function isStyleForced() + { + return $this->forceStyle; + } + + /** + * @param array $themes + * + * @throws InvalidStyleException + * @throws \InvalidArgumentException + */ + public function setThemes(array $themes) + { + $this->themes = []; + foreach ($themes as $name => $styles) { + $this->addTheme($name, $styles); + } + } + + /** + * @param string $name + * @param array|string $styles + * + * @throws \InvalidArgumentException + * @throws InvalidStyleException + */ + public function addTheme($name, $styles) + { + if (is_string($styles)) { + $styles = [$styles]; + } + if (! is_array($styles)) { + throw new \InvalidArgumentException('Style must be string or array.'); + } + + foreach ($styles as $style) { + if (! $this->isValidStyle($style)) { + throw new InvalidStyleException($style); + } + } + + $this->themes[$name] = $styles; + } + + /** + * @return array + */ + public function getThemes() + { + return $this->themes; + } + + /** + * @param string $name + * @return bool + */ + public function hasTheme($name) + { + return isset($this->themes[$name]); + } + + /** + * @param string $name + */ + public function removeTheme($name) + { + unset($this->themes[$name]); + } + + /** + * @codeCoverageIgnore + * + * @return bool + */ + public function isSupported() + { + if (DIRECTORY_SEPARATOR === '\\') { + // phpcs:ignore Generic.PHP.NoSilencedErrors,PHPCompatibility.FunctionUse.NewFunctions.sapi_windows_vt100_supportFound + if (function_exists('sapi_windows_vt100_support') && @sapi_windows_vt100_support(STDOUT)) { + return true; + } elseif (getenv('ANSICON') !== false || getenv('ConEmuANSI') === 'ON') { + return true; + } + + return false; + } else { + // phpcs:ignore Generic.PHP.NoSilencedErrors + return function_exists('posix_isatty') && @posix_isatty(STDOUT); + } + } + + /** + * @codeCoverageIgnore + * + * @return bool + */ + public function are256ColorsSupported() + { + if (DIRECTORY_SEPARATOR === '\\') { + // phpcs:ignore Generic.PHP.NoSilencedErrors,PHPCompatibility.FunctionUse.NewFunctions.sapi_windows_vt100_supportFound + return function_exists('sapi_windows_vt100_support') && @sapi_windows_vt100_support(STDOUT); + } else { + return strpos(getenv('TERM'), '256color') !== false; + } + } + + /** + * @return array + */ + public function getPossibleStyles() + { + return array_keys($this->styles); + } + + /** + * @param string $name + * @return string[] + */ + private function themeSequence($name) + { + $sequences = []; + foreach ($this->themes[$name] as $style) { + $sequences[] = $this->styleSequence($style); + } + + return $sequences; + } + + /** + * @param string $style + * @return string + */ + private function styleSequence($style) + { + if (array_key_exists($style, $this->styles)) { + return $this->styles[$style]; + } + + if (! $this->are256ColorsSupported()) { + return null; + } + + preg_match(self::COLOR256_REGEXP, $style, $matches); + + $type = $matches[1] === 'bg_' ? self::BACKGROUND : self::FOREGROUND; + $value = $matches[2]; + + return "$type;5;$value"; + } + + /** + * @param string $style + * @return bool + */ + private function isValidStyle($style) + { + return array_key_exists($style, $this->styles) || preg_match(self::COLOR256_REGEXP, $style); + } + + /** + * @param string|int $value + * @return string + */ + private function escSequence($value) + { + return "\033[{$value}m"; + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..b2b3868 --- /dev/null +++ b/package.json @@ -0,0 +1,20 @@ +{ + "private": true, + "scripts": { + "dev:css": "npx tailwindcss -i resources/css/plugin.css -o resources/dist/skeleton.css --postcss --watch", + "dev:js": "esbuild resources/js/plugin.js --bundle --sourcemap=inline --outfile=resources/dist/skeleton.js --watch", + "build:css": "npx tailwindcss -i resources/css/plugin.css -o resources/dist/skeleton.css --postcss --minify", + "build:js": "esbuild resources/js/plugin.js --bundle --minify --outfile=resources/dist/skeleton.js", + "build:purge": "filament-purge -i resources/dist/skeleton.css -o resources/dist/skeleton.css", + "dev": "npm-run-all --parallel dev:*", + "build": "npm-run-all build:*" + }, + "devDependencies": { + "@awcodes/filament-plugin-purge": "^1.0.2", + "autoprefixer": "^10.4.7", + "esbuild": "^0.8.57", + "npm-run-all": "^4.1.5", + "postcss": "^8.4.14", + "tailwindcss": "^3.1.6" + } +} \ No newline at end of file diff --git a/pint.json b/pint.json new file mode 100644 index 0000000..304d8f3 --- /dev/null +++ b/pint.json @@ -0,0 +1,11 @@ +{ + "preset": "laravel", + "rules": { + "blank_line_before_statement": true, + "concat_space": { + "spacing": "one" + }, + "method_argument_space": true, + "single_trait_insert_per_statement": true + } +} diff --git a/postcss.config.js b/postcss.config.js new file mode 100644 index 0000000..12a703d --- /dev/null +++ b/postcss.config.js @@ -0,0 +1,6 @@ +module.exports = { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +}; diff --git a/resources/css/plugin.css b/resources/css/plugin.css new file mode 100644 index 0000000..65dd5f6 --- /dev/null +++ b/resources/css/plugin.css @@ -0,0 +1 @@ +@tailwind utilities; diff --git a/resources/dist/.gitkeep b/resources/dist/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/resources/js/plugin.js b/resources/js/plugin.js new file mode 100644 index 0000000..e69de29 diff --git a/resources/lang/en/.gitkeep b/resources/lang/en/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/SkeletonServiceProvider.php b/src/SkeletonServiceProvider.php index ad24154..94a586c 100644 --- a/src/SkeletonServiceProvider.php +++ b/src/SkeletonServiceProvider.php @@ -3,8 +3,38 @@ namespace VendorName\Skeleton; use Filament\PluginServiceProvider; +use Spatie\LaravelPackageTools\Package; class SkeletonServiceProvider extends PluginServiceProvider { public static string $name = 'skeleton'; + + protected array $resources = [ + // CustomResource::class, + ]; + + protected array $pages = [ + // CustomPage::class, + ]; + + protected array $widgets = [ + // CustomWidget::class, + ]; + + protected array $styles = [ + 'plugin-skeleton' => __DIR__ . '/../dist/skeleton.css', + ]; + + protected array $scripts = [ + 'plugin-skeleton' => __DIR__ . '/../dist/skeleton.js', + ]; + + // protected array $beforeCoreScripts = [ + // 'plugin-skeleton' => __DIR__ . '/../dist/skeleton.js', + // ]; + + public function configurePackage(Package $package): void + { + $package->name(static::$name); + } } diff --git a/tailwind.config.js b/tailwind.config.js new file mode 100644 index 0000000..96ce29b --- /dev/null +++ b/tailwind.config.js @@ -0,0 +1,21 @@ +const colors = require("tailwindcss/colors"); + +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: ["./resources/views/**/*.blade.php", "./src/**/*.php"], + darkMode: "class", + theme: { + extend: { + colors: { + danger: colors.rose, + primary: colors.yellow, + success: colors.green, + warning: colors.amber, + }, + }, + }, + corePlugins: { + preflight: false, + }, + plugins: [], +};