diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 80a788c..ea26ad4 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -11,4 +11,4 @@ contact_links: about: Learn how to notify us for sensitive bugs - name: Report a bug url: https://github.com/:vendor_name/:package_name/issues/new - about: Report a reproducable bug + about: Report a reproducible bug diff --git a/.github/workflows/dependabot-auto-merge.yml b/.github/workflows/dependabot-auto-merge.yml index a9ffee9..6a79ba0 100644 --- a/.github/workflows/dependabot-auto-merge.yml +++ b/.github/workflows/dependabot-auto-merge.yml @@ -1,4 +1,5 @@ -name: dependabot-auto-merge +name: Dependabot Auto Merge + on: pull_request_target permissions: @@ -29,4 +30,4 @@ jobs: run: gh pr merge --auto --merge "$PR_URL" env: PR_URL: ${{github.event.pull_request.html_url}} - GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} \ No newline at end of file + GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} diff --git a/.github/workflows/fix-php-code-style-issues.yml b/.github/workflows/fix-php-code-style-issues.yml index 4ecdb9f..1c67e73 100644 --- a/.github/workflows/fix-php-code-style-issues.yml +++ b/.github/workflows/fix-php-code-style-issues.yml @@ -1,4 +1,4 @@ -name: Fix PHP code style issues +name: Fix PHP Code Styling on: [push] @@ -18,4 +18,4 @@ jobs: - name: Commit changes uses: stefanzweifel/git-auto-commit-action@v4 with: - commit_message: Fix styling \ No newline at end of file + commit_message: Fix styling diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 3efc226..20dfd1e 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -1,4 +1,4 @@ -name: run-tests +name: Run Tests on: push: @@ -44,4 +44,4 @@ jobs: composer update --${{ matrix.stability }} --prefer-dist --no-interaction - name: Execute tests - run: vendor/bin/pest \ No newline at end of file + run: vendor/bin/pest diff --git a/.github/workflows/update-changelog.yml b/.github/workflows/update-changelog.yml index 7787ca1..e5d1bf4 100644 --- a/.github/workflows/update-changelog.yml +++ b/.github/workflows/update-changelog.yml @@ -1,4 +1,4 @@ -name: "Update Changelog" +name: Update Changelog on: release: @@ -25,4 +25,4 @@ jobs: with: branch: main commit_message: Update CHANGELOG - file_pattern: CHANGELOG.md \ No newline at end of file + file_pattern: CHANGELOG.md diff --git a/composer.json b/composer.json index a9e92d4..26a8d2e 100644 --- a/composer.json +++ b/composer.json @@ -7,6 +7,10 @@ ":package_slug" ], "homepage": "https://github.com/:vendor_slug/:package_slug", + "support": { + "issues": "https://github.com/:vendor_slug/:package_slug/issues", + "source": "https://github.com/:vendor_slug/:package_slug" + }, "license": "MIT", "authors": [ { @@ -17,7 +21,9 @@ ], "require": { "php": "^8.0", - "filament/filament": "^2.0", + "filament/filament": "^3.0", + "filament/forms": "^3.0", + "filament/tables": "^3.0", "spatie/laravel-package-tools": "^1.13.5", "illuminate/contracts": "^9.0" }, diff --git a/configure.php b/configure.php index e3ae32b..86cab15 100644 --- a/configure.php +++ b/configure.php @@ -17,40 +17,89 @@ $vendorSlug = slugify($vendorName); $vendorNamespace = ucwords($vendorName); $vendorNamespace = ask('Vendor namespace', $vendorNamespace); -$currentDirectory = getcwd(); -$folderName = basename($currentDirectory); +$folderName = basename(getcwd()); $packageName = ask('Package name', $folderName); $packageSlug = slugify($packageName); -$packageSlugWithoutPrefix = remove_prefix('laravel-', $packageSlug); +$packageSlugWithoutPrefix = remove_prefix('filament-', $packageSlug); $className = title_case($packageName); $className = ask('Class name', $className); -$description = ask('Package description', "This is my package {$packageSlug}"); +$description = ask('Package description'); $usePhpStan = confirm('Enable PhpStan?', true); $usePint = confirm('Enable Pint?', true); +$useDependabot = confirm('Enable Dependabot?', true); +$useLaravelRay = confirm('Use Ray for debugging?', true); $useUpdateChangelogWorkflow = confirm('Use automatic changelog updater workflow?', true); -writeln('------'); -writeln("Author : {$authorName} ({$authorUsername}, {$authorEmail})"); -writeln("Vendor : {$vendorName} ({$vendorSlug})"); -writeln("Package : {$packageSlug} <{$description}>"); -writeln("Namespace : {$vendorNamespace}\\{$className}"); -writeln("Class name : {$className}"); -writeln('---'); -writeln('Packages & Utilities'); -writeln('Use Larastan/PhpStan : '.($usePhpStan ? 'yes' : 'no')); -writeln('Use Pint : '.($usePint ? 'yes' : 'no')); -writeln('Use Auto-Changelog : '.($useUpdateChangelogWorkflow ? 'yes' : 'no')); -writeln('------'); +$isTheme = confirm("Is this a custom theme?"); +$formsOnly = ! $isTheme && confirm("Is this for Forms only?"); +$tablesOnly = ! $formsOnly && confirm("Is this for Tables only?"); +writeln("\r"); +writeln('------'); +writeln("Author : \e[0;36m{$authorName} ({$authorUsername}, {$authorEmail})\e[0m"); +writeln("Vendor : \e[0;36m{$vendorName} ({$vendorSlug})\e[0m"); +writeln('Package : '."\e[0;36m".$packageSlug.($description ? ' <{$description}>' : '')."\e[0m"); +writeln("Namespace : \e[0;36m{$vendorNamespace}\\{$className}\e[0m"); +writeln("Class name : \e[0;36m{$className}\e[0m"); +writeln('---'); +writeln("\e[1;37mPackages & Utilities\e[0m"); +writeln('Larastan/PhpStan : '.($usePhpStan ? "\e[0;32mYes" : "\e[0;31mNo")."\e[0m"); +writeln('Pint : '.($usePint ? "\e[0;32mYes" : "\e[0;31mNo")."\e[0m"); +writeln('Use Dependabot : '.($useDependabot ? "\e[0;32mYes" : "\e[0;31mNo")."\e[0m"); +writeln('Use Ray App : '.($useLaravelRay ? "\e[0;32mYes" : "\e[0;31mNo")."\e[0m"); +writeln('Auto-Changelog : '.($useUpdateChangelogWorkflow ? "\e[0;32mYes" : "\e[0;31mNo")."\e[0m"); +if ($formsOnly) { + writeln("Filament/Forms : \e[0;32mYes\e[0m"); +} elseif ($tablesOnly) { + writeln("Filament/Tables : \e[0;32mYes\e[0m"); +} else { + writeln("Filament/Filament : \e[0;32mYes\e[0m"); +} +writeln('------'); +writeln("\r"); writeln('This script will replace the above values in all relevant files in the project directory.'); +writeln("\r"); if (! confirm('Modify files?', true)) { exit(1); } +if ($formsOnly) { + safeUnlink(__DIR__.'/src/SkeletonTheme.php'); + + remove_composer_filament_deps([ + 'filament/filament', + 'filament/tables', + ]); +} elseif ($tablesOnly) { + safeUnlink(__DIR__.'/src/SkeletonTheme.php'); + + remove_composer_filament_deps([ + 'filament/filament', + 'filament/forms', + ]); +} else { + if ($isTheme) { + safeUnlink(__DIR__ . '/src/SkeletonServiceProvider.php'); + remove_package_script(['purge']); + remove_package_script(['dev:scripts']); + remove_package_script(['build:scripts']); + remove_package_script(['@awcodes/filament-plugin-purge']); + remove_package_script(['esbuild']); + replace_in_file(__DIR__.'/package.json', [' && npm run purge' => '']); + } else { + safeUnlink(__DIR__.'/src/SkeletonTheme.php'); + } + + remove_composer_filament_deps([ + 'filament/forms', + 'filament/tables', + ]); +} + $files = (str_starts_with(strtoupper(PHP_OS), 'WIN') ? replaceForWindows() : replaceForAllOtherOSes()); foreach ($files as $file) { @@ -72,23 +121,23 @@ foreach ($files as $file) { match (true) { str_contains($file, determineSeparator('src/Skeleton.php')) => rename($file, determineSeparator('./src/'.$className.'.php')), str_contains($file, determineSeparator('src/SkeletonServiceProvider.php')) => rename($file, determineSeparator('./src/'.$className.'ServiceProvider.php')), + str_contains($file, determineSeparator('src/SkeletonTheme.php')) => rename($file, determineSeparator('./src/'.$className.'Theme.php')), str_contains($file, determineSeparator('src/Facades/Skeleton.php')) => rename($file, determineSeparator('./src/Facades/'.$className.'.php')), str_contains($file, determineSeparator('src/Commands/SkeletonCommand.php')) => rename($file, determineSeparator('./src/Commands/'.$className.'Command.php')), str_contains($file, determineSeparator('database/migrations/create_skeleton_table.php.stub')) => rename($file, determineSeparator('./database/migrations/create_'.$packageSlugWithoutPrefix.'_table.php.stub')), str_contains($file, determineSeparator('config/skeleton.php')) => rename($file, determineSeparator('./config/'.$packageSlugWithoutPrefix.'.php')), - str_contains($file, 'README.md') => remove_readme_paragraphs($file), + str_contains($file, 'README.md') => remove_tag($file, 'delete'), default => [], }; } -if (! $usePint) { - safeUnlink(__DIR__.'/.github/workflows/fix-php-code-style-issues.yml'); +if (! $useDependabot) { + safeUnlink(__DIR__.'/.github/dependabot.yml'); + safeUnlink(__DIR__.'/.github/workflows/dependabot-auto-merge.yml'); +} - remove_composer_deps([ - 'laravel/pint', - ]); - - remove_composer_script(['pint']); +if (! $useLaravelRay) { + remove_composer_deps(['spatie/laravel-ray']); } if (! $usePhpStan) { @@ -109,6 +158,16 @@ if (! $usePhpStan) { ]); } +if (! $usePint) { + safeUnlink(__DIR__.'/.github/workflows/fix-php-code-style-issues.yml'); + + remove_composer_deps([ + 'laravel/pint', + ]); + + remove_composer_script(['pint']); +} + if (! $useUpdateChangelogWorkflow) { safeUnlink(__DIR__.'/.github/workflows/update-changelog.yml'); } @@ -119,9 +178,8 @@ 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.': ')); + $def = $default ? "\e[0;33m ({$default})" : ''; + $answer = readline("\e[0;32m" . $question.$def . ": \e[0m"); if (! $answer) { return $default; @@ -132,11 +190,9 @@ function ask(string $question, string $default = ''): string function confirm(string $question, bool $default = false): bool { - $consoleColor = new ConsoleColor(); - $answer = ask($question, ($default ? 'Y/n' : 'y/N')); - if (! $answer) { + if (strtolower($answer) === 'y/n') { return $default; } @@ -153,17 +209,6 @@ 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), '-')); @@ -197,7 +242,7 @@ function remove_prefix(string $prefix, string $content): string return $content; } -function remove_composer_deps(array $names) +function remove_composer_deps(array $names): void { $data = json_decode(file_get_contents(__DIR__.'/composer.json'), true); @@ -210,7 +255,20 @@ function remove_composer_deps(array $names) file_put_contents(__DIR__.'/composer.json', json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)); } -function remove_composer_script(array $scriptNames) +function remove_composer_filament_deps(array $names): void +{ + $data = json_decode(file_get_contents(__DIR__.'/composer.json'), true); + + foreach ($data['require'] as $name => $version) { + if (in_array($name, $names, true)) { + unset($data['require'][$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): void { $data = json_decode(file_get_contents(__DIR__.'/composer.json'), true); @@ -233,17 +291,57 @@ function remove_composer_script(array $scriptNames) 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 +function remove_package_script(array $scriptNames): void +{ + $data = json_decode(file_get_contents(__DIR__.'/package.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; + } + } + + foreach ($data['devDependencies'] as $name => $script) { + if (is_array($script)) { + foreach ($script as $k => $s) { + if (in_array($s, $scriptNames)) { + unset($data['devDependencies'][$name][$k]); + + break; + } + } + } elseif (in_array($name, $scriptNames)) { + unset($data['devDependencies'][$name]); + + break; + } + } + + file_put_contents(__DIR__.'/package.json', json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | + JSON_UNESCAPED_UNICODE)); +} + +function remove_tag(string $file, string $tag): void { $contents = file_get_contents($file); file_put_contents( $file, - preg_replace('/.*/s', '', $contents) ?: $contents + preg_replace('/.*/s', '', $contents) ?: $contents ); } -function safeUnlink(string $filename) +function safeUnlink(string $filename): void { if (file_exists($filename) && is_file($filename)) { unlink($filename); @@ -264,301 +362,3 @@ 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 index fd52968..74f1cc9 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,6 @@ "postcss": "^8.4.14", "prettier": "^2.7.1", "prettier-plugin-tailwindcss": "^0.1.13", - "tailwindcss": "^3.1.6" + "tailwindcss": "^3.2" } } diff --git a/src/Commands/SkeletonCommand.php b/src/Commands/SkeletonCommand.php new file mode 100644 index 0000000..3e5f628 --- /dev/null +++ b/src/Commands/SkeletonCommand.php @@ -0,0 +1,19 @@ +comment('All done'); + + return self::SUCCESS; + } +} diff --git a/src/Facades/Skeleton.php b/src/Facades/Skeleton.php new file mode 100644 index 0000000..1fa9076 --- /dev/null +++ b/src/Facades/Skeleton.php @@ -0,0 +1,16 @@ + __DIR__.'/../resources/dist/skeleton.css', - ]; - - protected array $scripts = [ - 'plugin-skeleton' => __DIR__.'/../resources/dist/skeleton.js', - ]; - - // protected array $beforeCoreScripts = [ - // 'plugin-skeleton' => __DIR__ . '/../resources/dist/skeleton.js', - // ]; - public function configurePackage(Package $package): void { - $package->name(static::$name); + $package->name(static::$name) + ->hasConfigFile() + ->hasViews() + ->hasMigration('create_skeleton_table') + ->hasCommand(SkeletonCommand::class); } + + public function packageRegistered(): void + { + parent::packageRegistered(); + + $this->app->bind('skeleton', function (): Skeleton { + return new Skeleton(); + }); + } + + public function packageBooted(): void + { + parent::packageBooted(); + } + + protected function getAssetPackage(): ?string + { + return 'skeleton'; + } + + /** + * @return array + */ + protected function getAssets(): array + { + return [ +// AlpineComponent::make('skeleton', __DIR__ . '/../resources/dist/components/skeleton.js'), +// Css::make('echo', __DIR__ . '/../resources/dist/skeleton.js'), +// Js::make('echo', __DIR__ . '/../resources/dist/skeleton.js'), + ]; + } + } diff --git a/src/SkeletonTheme.php b/src/SkeletonTheme.php new file mode 100644 index 0000000..a2be177 --- /dev/null +++ b/src/SkeletonTheme.php @@ -0,0 +1,31 @@ +theme('skeleton'); + } + + public function boot(Context $context): void + { + // + } +}