You've already forked php-flasher
mirror of
https://github.com/php-flasher/php-flasher.git
synced 2026-04-05 12:32:55 +01:00
Compare commits
392 Commits
v2.1.5
...
881468ac26
| Author | SHA1 | Date | |
|---|---|---|---|
| 881468ac26 | |||
| 2bf87f7ae9 | |||
| 58123f259c | |||
| d427132437 | |||
| f372dcf70e | |||
| c4f1b059a3 | |||
| df4b85c0fd | |||
| e0766c1198 | |||
| e4337b0b63 | |||
| bd8169619e | |||
| 0d25c72743 | |||
| d4abef58eb | |||
| e126813835 | |||
| 5612d4d705 | |||
| 9454b2d155 | |||
| d39159cf90 | |||
| 76d63c03ce | |||
| 286fe5143e | |||
| f399bc912d | |||
| 98336b98bf | |||
| 50ffa722a5 | |||
| 93fc3c00e8 | |||
| e783943933 | |||
| f3d72c88c9 | |||
| 63b9083782 | |||
| 1f7d884c4d | |||
| 88f7546b50 | |||
| cbd753371b | |||
| 04d1e42fa3 | |||
| 67b24f24bb | |||
| b136cfcf6e | |||
| fd65254d63 | |||
| 33ac9013d5 | |||
| 1cc6a7c537 | |||
| dfe9a12fe1 | |||
| 8074bb1f90 | |||
| 03942aa634 | |||
| 6abae0bdde | |||
| 05c15399ac | |||
| 1bd85021d9 | |||
| 359e6de361 | |||
| e417105f7a | |||
| abd70c1d4b | |||
| 9acddbda52 | |||
| 7d6e9b46b8 | |||
| f1051e1d7f | |||
| 87da42fdea | |||
| 4d9cda22cf | |||
| c58f3c7b40 | |||
| 47eb66e874 | |||
| 30de24f054 | |||
| 162ea87330 | |||
| 8cda9d1eb1 | |||
| 6d314dbc07 | |||
| ad5c0f56dd | |||
| fd36c2ec0c | |||
| 5202c86107 | |||
| 9e7bb17faa | |||
| 83dc9e49dc | |||
| 1d81de581b | |||
| 2ebdbecda6 | |||
| 851e0a00ed | |||
| d9b0b6998e | |||
| ed992d78f6 | |||
| 0612a3bb61 | |||
| c9a61ba69c | |||
| f9746f607b | |||
| 18c2233baa | |||
| 08c242b45a | |||
| cd53ceb139 | |||
| 549c36eeee | |||
| ea0dccc961 | |||
| d33de77835 | |||
| 62848e0fd1 | |||
| c5059adac7 | |||
| 4145b870dd | |||
| 18a31f578b | |||
| f20bdebda0 | |||
| f9807e91e2 | |||
| e35339dca9 | |||
| f9bef40ae6 | |||
| 670e40dc97 | |||
| 2b0e736d28 | |||
| b79902779e | |||
| 8779de6c62 | |||
| c074feea05 | |||
| 033d650497 | |||
| 913f7b9d17 | |||
| 9eb6dcf8fa | |||
| 06f75b21eb | |||
| 0fe2e3e38e | |||
| 3ee5ba2909 | |||
| ca1a38d282 | |||
| 917b2c8f06 | |||
| 80cf92af09 | |||
| 82d0bc5a26 | |||
| 32055b1e87 | |||
| 9c07b5a72e | |||
| fdfd8e0b50 | |||
| 18712ba51e | |||
| abc8cf2569 | |||
| e1e3f01dce | |||
| 5aa8500683 | |||
| cea67fe813 | |||
| 3a47e100a0 | |||
| 93c5e987fc | |||
| 151c4f7778 | |||
| a5849a615b | |||
| 1801e187ac | |||
| 6eede92db6 | |||
| 0e04125627 | |||
| aeca5b5ee7 | |||
| 1b2f45f964 | |||
| e70d40ef04 | |||
| 0b9cfe80d5 | |||
| 767939a38c | |||
| d7234c64a2 | |||
| 194eab473e | |||
| 521746f813 | |||
| 34d780b0b7 | |||
| 61f991f379 | |||
| cc9fa57c4a | |||
| 613c73d7b6 | |||
| 9239063159 | |||
| 2e61a0539f | |||
| 548044bd7f | |||
| 3f920f2c01 | |||
| 65e9125539 | |||
| a0873c0082 | |||
| 1c5b533126 | |||
| f78824b8d9 | |||
| e212c0157e | |||
| fcf5c63f58 | |||
| ea164fde17 | |||
| 611fda9c61 | |||
| 21348f384d | |||
| 8f594698c7 | |||
| d65300a0e9 | |||
| a002590d56 | |||
| 5a4d46b46b | |||
| 0232edc9bd | |||
| 1c5fbbba9a | |||
| 15da40c582 | |||
| 8c77e96eb6 | |||
| 91ab4fa0f4 | |||
| b08117853a | |||
| 2417333107 | |||
| 358ad11c4d | |||
| a7823205ce | |||
| 50d6acfa94 | |||
| dd3c9f74f0 | |||
| fac5ca638a | |||
| 09199d8b56 | |||
| d9c65d274b | |||
| bde270a483 | |||
| c454fbc768 | |||
| 17a0e756d9 | |||
| 5ee7d58d7c | |||
| e0b93784bd | |||
| 18663b3214 | |||
| 7cf3de856e | |||
| e0cbc53c76 | |||
| b5bf2325be | |||
| e3158290f3 | |||
| 4070978256 | |||
| d96a953488 | |||
| ea8391eb6b | |||
| 3fc0d83dd6 | |||
| 1cb12c819b | |||
| f9d79f4589 | |||
| a3ce6a5262 | |||
| ff2cc1dc65 | |||
| 2cef5b98b2 | |||
| d7ecfb69a9 | |||
| 4909da7ba8 | |||
| f854ed4315 | |||
| 424617103f | |||
| 8dd56001db | |||
| e1ae7e215c | |||
| 730c13c447 | |||
| 12b0842cdd | |||
| 93ca18a67b | |||
| 1022991877 | |||
| 4345f2aa91 | |||
| 56dd1cea4c | |||
| 315a54eb43 | |||
| 82f2c69d65 | |||
| 91993e438b | |||
| 977c645c45 | |||
| 7a083efea0 | |||
| 5448e54f77 | |||
| c92105377d | |||
| 5cf68f2e34 | |||
| 68d7bfadce | |||
| ca6e75ba9d | |||
| 3407e309da | |||
| dce23cc288 | |||
| c1cc26379d | |||
| cc0658b3fe | |||
| a2abd9455a | |||
| 8d160a6659 | |||
| 8e6f0e8c88 | |||
| 4471ae6135 | |||
| 6d162c7f95 | |||
| 4f8e179fb8 | |||
| 53d7795292 | |||
| eec4b88872 | |||
| 37ac39e2ec | |||
| ef05362467 | |||
| 05229b0b42 | |||
| 28ca9d1370 | |||
| 03c358ce44 | |||
| 0edf9cc711 | |||
| 04685fad82 | |||
| 2bfc7ec5d4 | |||
| 4ef7a12484 | |||
| 4f09f06e07 | |||
| 00c8273272 | |||
| 2a7657b09c | |||
| 24d3c90752 | |||
| 5f4a8beaa3 | |||
| 70e08fc913 | |||
| f0a11e6600 | |||
| 66704f6368 | |||
| c18fbd1124 | |||
| 1899de104f | |||
| cd3ef599e1 | |||
| eb537353c2 | |||
| 4b1b747abe | |||
| 56109d9ed0 | |||
| a80c04bb19 | |||
| cd2c28ff11 | |||
| 3c79064e8d | |||
| 1e87cf5380 | |||
| 6dbef1d819 | |||
| c03c28533b | |||
| 59a2e502c8 | |||
| 3cb6ea7ed7 | |||
| bb83f55711 | |||
| ffbb8e5053 | |||
| aa82f13e08 | |||
| e8cd7a4595 | |||
| 568e3583b9 | |||
| 113e609b55 | |||
| edd684cd7c | |||
| 302de1f212 | |||
| d0bf147008 | |||
| 5d7145ff65 | |||
| 2faa760217 | |||
| eb0d0fbb6d | |||
| ccaab5b7e5 | |||
| 2ecfdef874 | |||
| 49e287f987 | |||
| 60c19498e3 | |||
| 9e59dc83fe | |||
| f39aaa7de5 | |||
| 68ae6dc9cb | |||
| 356672c634 | |||
| eff520316e | |||
| fa3012a711 | |||
| 27024721ea | |||
| 50a8b334be | |||
| 402b443f17 | |||
| 220284a892 | |||
| 5d81a1f0f1 | |||
| 5b8e6c64ff | |||
| 4b2edce0e4 | |||
| ff32c639ed | |||
| bad7544cf8 | |||
| a05d72d945 | |||
| 4672332012 | |||
| b4682b462a | |||
| 6ea30eb6d4 | |||
| b451da2141 | |||
| b5517bedcf | |||
| f411c6e3cb | |||
| 5a769cffc8 | |||
| dae72342b4 | |||
| ea47e9043b | |||
| 3b42b1a862 | |||
| e1d7ae94ee | |||
| 1945e03640 | |||
| 00eadbe207 | |||
| ee51cb775d | |||
| 0cf5e8f70d | |||
| 09d60d496b | |||
| b48d52d3bc | |||
| 9849c63d99 | |||
| e332c78512 | |||
| 0a148c10c2 | |||
| cf03403459 | |||
| a7491972e2 | |||
| 21c5cbd624 | |||
| 664c841e8d | |||
| 5f6837ea31 | |||
| 88ae4cfc4c | |||
| 042b314784 | |||
| a43cbd21ce | |||
| 39ca7b3e83 | |||
| 9d0bf7dca7 | |||
| 8913b6e0e2 | |||
| 0631e5953e | |||
| bdc7e85380 | |||
| be071be46b | |||
| b047c9016a | |||
| 8fa6054ada | |||
| c062ae7cf5 | |||
| 1c8b0bf081 | |||
| 5eddda90c5 | |||
| 46ed2f8468 | |||
| ecabbee799 | |||
| 568421c66b | |||
| ed4f6165c6 | |||
| 02f5fc0460 | |||
| a9aedc1236 | |||
| b4c9df4549 | |||
| 4d0b258ed7 | |||
| 71b21855c1 | |||
| f43878571b | |||
| fbe6238009 | |||
| 2ed68db245 | |||
| c81a99c755 | |||
| 3563e195bc | |||
| 47c7cd9ad8 | |||
| 6b9cf6b90c | |||
| 8d5cadcf66 | |||
| 3c2b4c5546 | |||
| 12c1ca36c7 | |||
| 9355c6a590 | |||
| 88e0de8417 | |||
| 8aa67d017c | |||
| 6b6204d264 | |||
| 50142d062e | |||
| b18069893b | |||
| fa414e7ae5 | |||
| 1d48abf3b7 | |||
| 43626a656b | |||
| c5a6e20552 | |||
| b02a55e6a6 | |||
| 176b616773 | |||
| 783822826c | |||
| 25ce040d00 | |||
| 6ae8779f8f | |||
| 7fafa513a2 | |||
| d20a7de308 | |||
| e1a6a85c76 | |||
| 565438eb9f | |||
| efea45f892 | |||
| f0bf6c61ab | |||
| f3b6183449 | |||
| d10e93b56f | |||
| b88afe29b9 | |||
| 13c72935ba | |||
| 7fee53a92a | |||
| 8ee2442b9c | |||
| 99484054f9 | |||
| 3be978fc53 | |||
| fe773941e4 | |||
| 63fc0d9640 | |||
| 4a83adb4f3 | |||
| 3d66271ac8 | |||
| 29cea6f9d3 | |||
| 47ad265fb4 | |||
| 99371ede9e | |||
| 6e8884d1d1 | |||
| 2c95b4e6ba | |||
| 4b3fb8f584 | |||
| 40e9e83e3a | |||
| 59ead448e9 | |||
| 1397e0bb59 | |||
| 56e610d6b0 | |||
| ba3dd5fe7f | |||
| d9699b7fe2 | |||
| ed742de9db | |||
| 8fdc809118 | |||
| dfdd28b869 | |||
| a539235d1a | |||
| df08f255d3 | |||
| 31d5cb6e8e | |||
| d2750dee8a | |||
| 43553ad8ad | |||
| 48b2c0fae0 | |||
| 0988fdca9d | |||
| a24159c3f0 | |||
| f9c9ecf18e | |||
| f93a908d25 | |||
| 1237b5f552 | |||
| bce970de5f | |||
| 8809cd9ddf | |||
| fdbc5fd270 | |||
| 3d5d8d3c9a | |||
| 9d1bbc5d9a |
@@ -1,3 +1,4 @@
|
||||
> 1%
|
||||
last 2 versions
|
||||
not dead
|
||||
not IE 11
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
github: yoeunes
|
||||
custom: https://www.paypal.com/paypalme/yoeunes
|
||||
|
||||
@@ -5,7 +5,28 @@ on:
|
||||
types: [ published ]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
name: Run Tests Before Publishing
|
||||
|
||||
steps:
|
||||
- name: 📥 Checkout Code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 🔧 Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20.x'
|
||||
cache: 'npm'
|
||||
|
||||
- name: 📦 Install Dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: ✅ Run Tests
|
||||
run: npm run test
|
||||
|
||||
publish-prime:
|
||||
needs: test
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
@@ -30,6 +51,7 @@ jobs:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
|
||||
publish-plugin:
|
||||
needs: test
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
name: 🧪 Run Tests & 🛠️ Static Analysis
|
||||
name: qa
|
||||
|
||||
on:
|
||||
push:
|
||||
@@ -10,6 +10,29 @@ on:
|
||||
- cron: '0 0 * * *' # Daily at midnight
|
||||
|
||||
jobs:
|
||||
javascript-tests:
|
||||
runs-on: ubuntu-latest
|
||||
name: JavaScript Tests
|
||||
|
||||
steps:
|
||||
- name: 📥 Checkout Code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 🔧 Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20.x'
|
||||
cache: 'npm'
|
||||
|
||||
- name: 📦 Install Dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: ✅ Run Tests
|
||||
run: npm run test
|
||||
|
||||
- name: 📊 Run Coverage
|
||||
run: npm run test:coverage
|
||||
|
||||
static-analysis:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
@@ -17,7 +40,7 @@ jobs:
|
||||
matrix:
|
||||
php: [ 8.2 ]
|
||||
|
||||
name: 🐘 PHP ${{ matrix.php }} Static Analysis
|
||||
name: php v${{ matrix.php }}
|
||||
|
||||
steps:
|
||||
- name: 📥 Checkout Code
|
||||
@@ -39,18 +62,19 @@ jobs:
|
||||
- name: 📦 Install Dependencies
|
||||
run: |
|
||||
composer config --global allow-plugins true
|
||||
composer install
|
||||
composer install --no-interaction --prefer-dist --optimize-autoloader
|
||||
|
||||
- name: 🧹 Run PHP CS Fixer (Code Style)
|
||||
run: vendor/bin/php-cs-fixer fix --dry-run
|
||||
run: vendor/bin/php-cs-fixer fix --dry-run --diff
|
||||
|
||||
- name: 🔍 Run PHPStan (Static Analysis)
|
||||
run: vendor/bin/phpstan analyse
|
||||
run: vendor/bin/phpstan analyse --no-progress
|
||||
|
||||
- name: 🚀 Run PHPLint (Syntax Check)
|
||||
run: vendor/bin/phplint
|
||||
|
||||
prime-test:
|
||||
needs: static-analysis
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
@@ -60,7 +84,7 @@ jobs:
|
||||
- { php: 8.3, phpunit: 10.5.* }
|
||||
- { php: 8.2, phpunit: 10.5.* }
|
||||
|
||||
name: 🐘 PHP ${{ matrix.php }}
|
||||
name: php v${{ matrix.php }}
|
||||
|
||||
steps:
|
||||
- name: 📥 Checkout code
|
||||
@@ -84,7 +108,7 @@ jobs:
|
||||
sed -i '/"require": {/,/},/d; /"require-dev": {/,/},/d' composer.json
|
||||
composer config --global allow-plugins true
|
||||
composer require "phpunit/phpunit:${{ matrix.phpunit }}" "mockery/mockery" "psr/container" --no-interaction --no-update
|
||||
composer update --prefer-lowest -W
|
||||
composer update --prefer-lowest -W --no-interaction --prefer-dist --optimize-autoloader
|
||||
|
||||
- name: ✅ Execute tests
|
||||
run: vendor/bin/phpunit --testsuite prime
|
||||
@@ -95,13 +119,17 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- { symfony: 7.2.*, php: 8.4, phpunit: 10.5.* }
|
||||
- { symfony: 7.2.*, php: 8.3, phpunit: 10.5.* }
|
||||
- { symfony: 8.0.x-dev, php: 8.4, phpunit: 10.5.* }
|
||||
- { symfony: 7.4.x-dev, php: 8.2, phpunit: 10.5.* }
|
||||
- { symfony: 7.3.*, php: 8.5, phpunit: 10.5.* }
|
||||
- { symfony: 7.3.*, php: 8.4, phpunit: 10.5.* }
|
||||
- { symfony: 7.3.*, php: 8.3, phpunit: 10.5.* }
|
||||
- { symfony: 7.3.*, php: 8.2, phpunit: 10.5.* }
|
||||
- { symfony: 7.2.*, php: 8.2, phpunit: 10.5.* }
|
||||
- { symfony: 7.1.*, php: 8.2, phpunit: 10.5.* }
|
||||
- { symfony: 7.0.*, php: 8.2, phpunit: 10.5.* }
|
||||
|
||||
name: 🌉 Symfony ${{ matrix.symfony }} PHP ${{ matrix.php }}
|
||||
name: symfony v${{ matrix.symfony }} x php v${{ matrix.php }}
|
||||
|
||||
steps:
|
||||
- name: 📥 Checkout code
|
||||
@@ -125,8 +153,22 @@ jobs:
|
||||
sed -i '/"require": {/,/},/d; /"require-dev": {/,/},/d' composer.json
|
||||
composer config --global allow-plugins true
|
||||
composer config extra.symfony.require "${{ matrix.symfony }}"
|
||||
|
||||
if [[ "${{ matrix.symfony }}" == *"-dev"* ]]; then
|
||||
echo "Setting minimum-stability to dev for ${{ matrix.symfony }}"
|
||||
composer config minimum-stability "dev"
|
||||
composer config prefer-stable true
|
||||
fi
|
||||
|
||||
composer require "symfony/config:${{ matrix.symfony }}" "symfony/console:${{ matrix.symfony }}" "symfony/dependency-injection:${{ matrix.symfony }}" "symfony/framework-bundle:${{ matrix.symfony }}" "symfony/http-kernel:${{ matrix.symfony }}" "symfony/translation:${{ matrix.symfony }}" "symfony/twig-bundle:${{ matrix.symfony }}" "phpunit/phpunit:${{ matrix.phpunit }}" "mockery/mockery" "psr/container" "monolog/monolog" --no-interaction --no-update
|
||||
composer update --prefer-lowest -W
|
||||
|
||||
if [[ "${{ matrix.symfony }}" == *"-dev"* ]]; then
|
||||
echo "Running composer update (latest dependencies)"
|
||||
composer update -W --no-interaction --prefer-dist --optimize-autoloader
|
||||
else
|
||||
echo "Running composer update --prefer-lowest"
|
||||
composer update --prefer-lowest -W --no-interaction --prefer-dist --optimize-autoloader
|
||||
fi
|
||||
|
||||
- name: ✅ Execute tests
|
||||
run: vendor/bin/phpunit --testsuite symfony
|
||||
@@ -137,10 +179,16 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- { laravel: 11.*, testbench: 9.*, php: 8.3, phpunit: 10.5.* }
|
||||
- { laravel: 13.x-dev, testbench: 11.x-dev, php: 8.5, phpunit: 11.5.* }
|
||||
- { laravel: 13.x-dev, testbench: 11.x-dev, php: 8.4, phpunit: 11.5.* }
|
||||
- { laravel: 13.x-dev, testbench: 11.x-dev, php: 8.3, phpunit: 11.5.* }
|
||||
- { laravel: 12.*, testbench: 10.*, php: 8.5, phpunit: 11.5.* }
|
||||
- { laravel: 12.*, testbench: 10.*, php: 8.4, phpunit: 11.5.* }
|
||||
- { laravel: 12.*, testbench: 10.*, php: 8.3, phpunit: 11.5.* }
|
||||
- { laravel: 12.*, testbench: 10.*, php: 8.2, phpunit: 11.5.* }
|
||||
- { laravel: 11.*, testbench: 9.*, php: 8.2, phpunit: 10.5.* }
|
||||
|
||||
name: 🏗 Laravel ${{ matrix.laravel }} PHP ${{ matrix.php }}
|
||||
name: laravel v${{ matrix.laravel }} x php v${{ matrix.php }}
|
||||
|
||||
steps:
|
||||
- name: 📥 Checkout code
|
||||
@@ -164,8 +212,22 @@ jobs:
|
||||
run: |
|
||||
sed -i '/\"require\": {/,/},/d; /\"require-dev\": {/,/},/d' composer.json
|
||||
composer config --global allow-plugins true
|
||||
|
||||
if [[ "${{ matrix.laravel }}" == *"-dev"* ]]; then
|
||||
echo "Setting minimum-stability to dev for ${{ matrix.laravel }}"
|
||||
composer config minimum-stability "dev"
|
||||
composer config prefer-stable true
|
||||
fi
|
||||
|
||||
composer require "laravel/framework:${{ matrix.laravel }}" "phpunit/phpunit:${{ matrix.phpunit }}" "orchestra/testbench:${{ matrix.testbench }}" --no-interaction --no-update
|
||||
composer update --prefer-lowest -W
|
||||
|
||||
if [[ "${{ matrix.laravel }}" == *"-dev"* ]]; then
|
||||
echo "Running composer update (latest dependencies)"
|
||||
composer update -W --no-interaction --prefer-dist --optimize-autoloader
|
||||
else
|
||||
echo "Running composer update --prefer-lowest"
|
||||
composer update --prefer-lowest -W --no-interaction --prefer-dist --optimize-autoloader
|
||||
fi
|
||||
|
||||
- name: ✅ Execute tests
|
||||
run: vendor/bin/phpunit --testsuite laravel
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
/vendor/
|
||||
/node_modules/
|
||||
|
||||
/coverage/
|
||||
|
||||
/.cache/php-cs-fixer/
|
||||
/.cache/phplint/
|
||||
/.cache/phpstan/
|
||||
@@ -14,6 +16,12 @@
|
||||
/taskfile.yml
|
||||
/phpstan.neon
|
||||
|
||||
/demo/laravel/node_modules/
|
||||
/demo/symfony/node_modules/
|
||||
|
||||
/npm-debug.log
|
||||
|
||||
/tests/Symfony/Fixtures/project/public/vendor/
|
||||
|
||||
src/**/vendor/
|
||||
src/**/composer.lock
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
{
|
||||
"upgrade": true,
|
||||
"target": "semver"
|
||||
"upgrade": true,
|
||||
"target": "semver",
|
||||
"format": "group",
|
||||
"color": true,
|
||||
"root": true
|
||||
}
|
||||
|
||||
Vendored
-1
@@ -1,2 +1 @@
|
||||
github: yoeunes
|
||||
custom: https://www.paypal.com/paypalme/yoeunes
|
||||
|
||||
+57
-1
@@ -1,6 +1,62 @@
|
||||
# CHANGELOG for 2.x
|
||||
|
||||
## [Unreleased](https://github.com/php-flasher/php-flasher/compare/v2.1.4...2.x)
|
||||
## [Unreleased](https://github.com/php-flasher/php-flasher/compare/v2.5.1...2.x)
|
||||
|
||||
## [v2.5.1](https://github.com/php-flasher/php-flasher/compare/v2.5.0...v2.5.1) - 2026-03-28
|
||||
|
||||
### Fixed
|
||||
|
||||
* fix [Laravel] Fix Laravel 13 JSON session serialization compatibility - StorageManager now handles both array and object formats returned by session
|
||||
|
||||
## [v2.5.0](https://github.com/php-flasher/php-flasher/compare/v2.1.4...v2.5.0) - 2026-03-07
|
||||
|
||||
### Added
|
||||
|
||||
* feature [Laravel] Improve Laravel Octane support by resetting FallbackSession static storage between requests to prevent notification leakage
|
||||
* feature [Symfony] Add FrankenPHP/Swoole/RoadRunner support with WorkerListener that implements ResetInterface and is tagged with kernel.reset
|
||||
* feature [Symfony] Add reset() method to FallbackSession for long-running process support
|
||||
* feature [Flasher] Add Hotwire/Turbo Drive support with turbo:before-cache event listener to clean up notifications before page caching
|
||||
* feature [Flasher] Add event dispatching system for all notification adapters and themes with Livewire integration:
|
||||
- [Toastr] Dispatch events: `flasher:toastr:click`, `flasher:toastr:close`, `flasher:toastr:show`, `flasher:toastr:hidden`
|
||||
- [Noty] Dispatch events: `flasher:noty:click`, `flasher:noty:close`, `flasher:noty:show`, `flasher:noty:hover`
|
||||
- [Notyf] Dispatch events: `flasher:notyf:click`, `flasher:notyf:dismiss`
|
||||
- [Themes] Dispatch events: `flasher:theme:click` (generic) and `flasher:theme:{name}:click` (specific)
|
||||
- [Laravel] Add LivewireListener classes for all adapters and themes to enable Livewire event handling
|
||||
* feature [Flasher] Add 16 notification themes: Amazon, Amber, Jade, Crystal, and more
|
||||
* feature [DX] Add `@method` annotations to FlasherInterface and NotificationFactoryInterface for better IDE autocompletion
|
||||
* feature [DX] Add Type::all() and Type::isValid() helper methods with PHPStan type narrowing
|
||||
* feature [DX] Add `@throws` annotations to FlasherContainer methods for better exception documentation
|
||||
* feature [DX] Add FlasherContainer::setContainer() method as convenient alias for testing
|
||||
* feature [DX] Add PHPStan type alias `NotificationType` for valid notification types
|
||||
|
||||
### Fixed
|
||||
|
||||
* fix [SweetAlert] Fix SweetAlertBuilder::question() bug where options parameter was being ignored
|
||||
* fix [Flasher] Fix potential runtime error in Envelope::toArray() when no PresentableStampInterface stamps exist
|
||||
* fix [Flasher] Use more specific \Random\RandomException in IdStamp instead of broad \Exception
|
||||
* fix [Flasher] Update Livewire navigation cleanup to use correct .fl-wrapper selector instead of unused .fl-no-cache class
|
||||
* fix [Flasher] Fix FilterCriteria uninitialized property error when constructed with empty array
|
||||
* fix [Flasher] Fix null comparison issues in PriorityCriteria, HopsCriteria, and DelayCriteria that relied on PHP's implicit null-to-0 coercion
|
||||
* fix [Flasher] Add type validation for callable factory return values in NotificationFactoryLocator with descriptive error messages
|
||||
* fix [Flasher] Add error handling for invalid regex patterns in ResponseExtension::isPathExcluded()
|
||||
* fix [Flasher] Fix ContentSecurityPolicyHandler parsing of CSP headers with trailing semicolons creating empty directive keys
|
||||
* fix [Flasher] Add reset() method to ContentSecurityPolicyHandler to fix CSP state leak in long-running processes (Octane, FrankenPHP)
|
||||
* fix [Flasher] Fix FilterEvent::setFilter() type inconsistency - now accepts FilterInterface instead of concrete Filter class
|
||||
* fix [Flasher] Remove redundant callable check in FlasherContainer::getContainer()
|
||||
* fix [Flasher] Fix NotificationStorageMethods::resolveResourceName() return type from ?string to string (never returns null)
|
||||
* fix [Flasher] Fix parameter name inconsistency in NotificationBuilderInterface::options() - changed $merge to $append to match implementation
|
||||
* fix [Flasher] Add type validation for callable presenter return values in ResponseManager with descriptive error messages
|
||||
* fix [Flasher] Fix FlasherPlugin::normalizePlugins() losing scripts/styles when both top-level and plugin-level configs are provided - replaced array union operator with array_merge
|
||||
* fix [Flasher] Simplify FlasherPlugin::normalizeFlashBag() by replacing redundant array union with direct array_merge
|
||||
* fix [Flasher] Fix array_merge() syntax in InstallCommand by removing unnecessary empty array
|
||||
* fix [Flasher] Add return type validation in FilterCriteria::apply() with proper exception handling
|
||||
|
||||
### Changed
|
||||
|
||||
* refactor [Flasher] Reduce theme configuration duplication by generating themes programmatically
|
||||
* refactor [Flasher] Standardize exception message format in PresetNotFoundException to use brackets like other exceptions
|
||||
* refactor [Flasher] Standardize exception message wording in CriteriaNotRegisteredException to use "not found" instead of "is not found"
|
||||
* refactor [SweetAlert] Replace @phpstan-ignore-line suppressions with proper @var annotations
|
||||
|
||||
## [v2.1.3](https://github.com/php-flasher/php-flasher/compare/v2.1.2...v2.1.3) - 2025-01-25
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024 PHPFlasher
|
||||
Copyright (c) 2024-present PHPFlasher
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -11,272 +11,323 @@
|
||||
</picture>
|
||||
</p>
|
||||
|
||||
<h1 align="center">Elegant Flash Notifications for PHP</h1>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://www.linkedin.com/in/younes--ennaji"><img src="https://img.shields.io/badge/author-@yoeunes-blue.svg" alt="Author Badge"></a>
|
||||
<a href="https://github.com/php-flasher/php-flasher"><img src="https://img.shields.io/badge/source-php--flasher/php--flasher-blue.svg" alt="Source Code Badge"></a>
|
||||
<a href="https://github.com/php-flasher/php-flasher/releases"><img src="https://img.shields.io/github/tag/php-flasher/flasher.svg" alt="GitHub Release Badge"></a>
|
||||
<a href="https://github.com/php-flasher/flasher/blob/master/LICENSE"><img src="https://img.shields.io/badge/license-MIT-brightgreen.svg" alt="License Badge"></a>
|
||||
<a href="https://packagist.org/packages/php-flasher/flasher"><img src="https://img.shields.io/packagist/dt/php-flasher/flasher.svg" alt="Packagist Downloads Badge"></a>
|
||||
<a href="https://github.com/php-flasher/php-flasher"><img src="https://img.shields.io/github/stars/php-flasher/php-flasher.svg" alt="GitHub Stars Badge"></a>
|
||||
<a href="https://packagist.org/packages/php-flasher/flasher"><img src="https://img.shields.io/packagist/php-v/php-flasher/flasher.svg" alt="Supported PHP Version Badge"></a>
|
||||
<strong>One line of PHP. Beautiful notifications. Zero JavaScript.</strong>
|
||||
</p>
|
||||
|
||||
## Table of Contents
|
||||
<p align="center">
|
||||
<a href="https://packagist.org/packages/php-flasher/flasher"><img src="https://img.shields.io/packagist/dt/php-flasher/flasher.svg?style=flat-square&label=downloads" alt="Downloads"></a>
|
||||
<a href="https://github.com/php-flasher/php-flasher"><img src="https://img.shields.io/github/stars/php-flasher/php-flasher.svg?style=flat-square&label=stars" alt="Stars"></a>
|
||||
<a href="https://github.com/php-flasher/php-flasher/releases"><img src="https://img.shields.io/github/v/release/php-flasher/flasher.svg?style=flat-square" alt="Release"></a>
|
||||
<a href="https://packagist.org/packages/php-flasher/flasher"><img src="https://img.shields.io/packagist/php-v/php-flasher/flasher.svg?style=flat-square" alt="PHP Version"></a>
|
||||
<a href="https://github.com/php-flasher/php-flasher/blob/2.x/LICENSE"><img src="https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square" alt="License"></a>
|
||||
</p>
|
||||
|
||||
- [About PHPFlasher](#about-phpflasher)
|
||||
- [Features](#features)
|
||||
- [Supported Versions](#supported-versions)
|
||||
- [Installation](#installation)
|
||||
- [Core Package](#core-package)
|
||||
- [Adapters](#adapters)
|
||||
- [Quick Start](#quick-start)
|
||||
- [Usage Examples](#usage-examples)
|
||||
- [Adapters Overview](#adapters-overview)
|
||||
- [Official Documentation](#official-documentation)
|
||||
- [Contributors and Sponsors](#contributors-and-sponsors)
|
||||
- [Contact](#contact)
|
||||
- [License](#license)
|
||||
<p align="center">
|
||||
<a href="https://php-flasher.io"><strong>Documentation</strong></a> ·
|
||||
<a href="https://php-flasher.io/playground"><strong>Live Playground</strong></a> ·
|
||||
<a href="https://github.com/php-flasher/php-flasher/issues"><strong>Report Bug</strong></a>
|
||||
</p>
|
||||
|
||||
## About PHPFlasher
|
||||
|
||||
PHPFlasher is an open-source tool that helps you add flash messages to your web applications. Flash messages are short notifications that provide feedback to users after they perform actions, such as submitting a form or encountering an error. These messages enhance the user experience by informing users about the outcomes of their actions.
|
||||
|
||||
PHPFlasher simplifies the process of integrating flash messages into **Laravel** and **Symfony** projects. It uses sessions to store messages, allowing you to set a message on one page and display it on another without complex setup.
|
||||
|
||||
## Features
|
||||
|
||||
- **Multiple Adapters**: Supports Laravel, Symfony, Toastr, Noty, SweetAlert, and more.
|
||||
- **Flexible Configuration**: Customize the appearance and behavior of flash messages.
|
||||
- **Extensible**: Easily integrate with various frontend libraries and frameworks.
|
||||
- **Intuitive API**: Simple functions to create and manage flash messages.
|
||||
|
||||
## Supported Versions
|
||||
|
||||
| PHPFlasher Version | PHP Version | Symfony Version | Laravel Version |
|
||||
|--------------------|-------------|-----------------|-----------------|
|
||||
| **v2.x** | ≥ 8.2 | ≥ 7.2 | ≥ 11 |
|
||||
| **v1.x** | ≥ 5.3 | ≥ 2.0 | ≥ 4.0 |
|
||||
|
||||
> **Note:** If your project uses PHP, Symfony, or Laravel versions below the requirements for PHPFlasher v2.x, please use [PHPFlasher v1.x](https://github.com/php-flasher/php-flasher/tree/1.x).
|
||||
|
||||
## Installation
|
||||
|
||||
### Core Package
|
||||
|
||||
Install the core PHPFlasher package via Composer:
|
||||
|
||||
- **For Laravel:**
|
||||
|
||||
```bash
|
||||
composer require php-flasher/flasher-laravel
|
||||
```
|
||||
|
||||
After installation, set up the necessary assets:
|
||||
|
||||
```shell
|
||||
php artisan flasher:install
|
||||
```
|
||||
|
||||
> **Note:** PHPFlasher automatically injects the necessary JavaScript and CSS assets into your Blade templates. No additional steps are required for asset injection.
|
||||
|
||||
- **For Symfony:**
|
||||
|
||||
```bash
|
||||
composer require php-flasher/flasher-symfony
|
||||
```
|
||||
|
||||
After installation, set up the necessary assets:
|
||||
|
||||
```shell
|
||||
php bin/console flasher:install
|
||||
```
|
||||
|
||||
> **Note:** PHPFlasher automatically injects the necessary JavaScript and CSS assets into your Twig templates. No additional steps are required for asset injection.
|
||||
|
||||
### Adapters
|
||||
|
||||
PHPFlasher provides various adapters for different frameworks and notification libraries. Below is an overview of available adapters:
|
||||
|
||||
#### Toastr
|
||||
|
||||
- [flasher-toastr](https://github.com/php-flasher/flasher-toastr) - Core Toastr Adapter
|
||||
- [flasher-toastr-laravel](https://github.com/php-flasher/flasher-toastr-laravel) - Laravel Adapter
|
||||
- [flasher-toastr-symfony](https://github.com/php-flasher/flasher-toastr-symfony) - Symfony Adapter
|
||||
|
||||
#### Noty
|
||||
|
||||
- [flasher-noty](https://github.com/php-flasher/flasher-noty) - Core Noty Adapter
|
||||
- [flasher-noty-laravel](https://github.com/php-flasher/flasher-noty-laravel) - Laravel Adapter
|
||||
- [flasher-noty-symfony](https://github.com/php-flasher/flasher-noty-symfony) - Symfony Adapter
|
||||
|
||||
#### Notyf
|
||||
|
||||
- [flasher-notyf](https://github.com/php-flasher/flasher-notyf) - Core Notyf Adapter
|
||||
- [flasher-notyf-laravel](https://github.com/php-flasher/flasher-notyf-laravel) - Laravel Adapter
|
||||
- [flasher-notyf-symfony](https://github.com/php-flasher/flasher-notyf-symfony) - Symfony Adapter
|
||||
|
||||
#### SweetAlert
|
||||
|
||||
- [flasher-sweetalert](https://github.com/php-flasher/flasher-sweetalert) - Core SweetAlert Adapter
|
||||
- [flasher-sweetalert-laravel](https://github.com/php-flasher/flasher-sweetalert-laravel) - Laravel Adapter
|
||||
- [flasher-sweetalert-symfony](https://github.com/php-flasher/flasher-sweetalert-symfony) - Symfony Adapter
|
||||
|
||||
For detailed installation and usage instructions for each adapter, refer to their respective [README.md](https://github.com/php-flasher/flasher-toastr).
|
||||
---
|
||||
|
||||
## Quick Start
|
||||
|
||||
To display a notification message, you can either use the `flash()` helper function or obtain an instance of `flasher` from the service container. Then, before returning a view or redirecting, call the desired method (`success()`, `error()`, etc.) and pass in the message to be displayed.
|
||||
|
||||
### Using the `flash()` Helper
|
||||
|
||||
```php
|
||||
class BookController
|
||||
{
|
||||
public function saveBook()
|
||||
{
|
||||
// Your logic here
|
||||
|
||||
flash('Your changes have been saved!');
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
}
|
||||
**Laravel:**
|
||||
```bash
|
||||
composer require php-flasher/flasher-laravel && php artisan flasher:install
|
||||
```
|
||||
|
||||
### Using the `flasher` Service
|
||||
|
||||
```php
|
||||
use Flasher\Prime\FlasherInterface;
|
||||
|
||||
class AnotherController
|
||||
{
|
||||
/**
|
||||
* If you prefer to use dependency injection
|
||||
*/
|
||||
public function register(FlasherInterface $flasher)
|
||||
{
|
||||
// Your logic here
|
||||
|
||||
$flasher->success('Your changes have been saved!');
|
||||
|
||||
// ... redirect or render the view
|
||||
}
|
||||
|
||||
public function update()
|
||||
{
|
||||
// Your logic here
|
||||
|
||||
app('flasher')->error('An error occurred while updating.'); // ony for laravel
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
}
|
||||
**Symfony:**
|
||||
```bash
|
||||
composer require php-flasher/flasher-symfony && php bin/console flasher:install
|
||||
```
|
||||
|
||||
## Usage Examples
|
||||
**That's it!** Now use it:
|
||||
|
||||
### Success Message
|
||||
```php
|
||||
flash()->success('Welcome aboard! Your account is ready.');
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Why PHPFlasher?
|
||||
|
||||
| | PHPFlasher | Others |
|
||||
|---|:---:|:---:|
|
||||
| **Zero JavaScript** | Write PHP only, frontend handled automatically | Requires manual JS setup |
|
||||
| **Auto Asset Injection** | CSS/JS injected automatically | Manual script tags needed |
|
||||
| **17 Built-in Themes** | Amazon, iOS, Slack, Material & more | Limited or no themes |
|
||||
| **4 Notification Libraries** | Toastr, SweetAlert, Noty, Notyf | Single library only |
|
||||
| **Livewire Integration** | Full event system support | Limited or none |
|
||||
| **RTL Support** | Built-in right-to-left | Often missing |
|
||||
| **Framework Agnostic** | Laravel, Symfony, or vanilla PHP | Framework-specific |
|
||||
|
||||
---
|
||||
|
||||
## Notification Types
|
||||
|
||||
```php
|
||||
flash()->success('Operation completed successfully!');
|
||||
flash()->error('Oops! Something went wrong.');
|
||||
flash()->warning('Please backup your data before continuing.');
|
||||
flash()->info('A new version is available for download.');
|
||||
```
|
||||
|
||||
### Error Message
|
||||
### With Titles
|
||||
|
||||
```php
|
||||
flash()->error('An error occurred.');
|
||||
flash()->success('Your changes have been saved.', 'Update Complete');
|
||||
flash()->error('Unable to connect to server.', 'Connection Failed');
|
||||
```
|
||||
|
||||
### Info Message
|
||||
### With Options
|
||||
|
||||
```php
|
||||
flash()->info('This is an informational message.');
|
||||
flash()->success('Profile updated!', [
|
||||
'position' => 'bottom-right',
|
||||
'timeout' => 10000,
|
||||
]);
|
||||
```
|
||||
|
||||
### Warning Message
|
||||
---
|
||||
|
||||
## 17 Beautiful Themes
|
||||
|
||||
PHPFlasher includes **17 professionally designed themes** ready to use:
|
||||
|
||||
```php
|
||||
flash()->warning('This is a warning message.');
|
||||
flash()->success('Welcome!', ['theme' => 'amazon']);
|
||||
flash()->success('Welcome!', ['theme' => 'ios']);
|
||||
flash()->success('Welcome!', ['theme' => 'slack']);
|
||||
flash()->success('Welcome!', ['theme' => 'material']);
|
||||
```
|
||||
|
||||
### Passing Options
|
||||
<details>
|
||||
<summary><strong>View All Themes</strong></summary>
|
||||
|
||||
| Theme | Style |
|
||||
|-------|-------|
|
||||
| `flasher` | Default clean design |
|
||||
| `amazon` | Amazon-inspired e-commerce |
|
||||
| `ios` | Apple iOS notifications |
|
||||
| `slack` | Slack messaging style |
|
||||
| `material` | Google Material Design |
|
||||
| `google` | Google notifications |
|
||||
| `facebook` | Facebook style |
|
||||
| `minimal` | Ultra-clean minimal |
|
||||
| `amber` | Warm amber tones |
|
||||
| `aurora` | Gradient effects |
|
||||
| `crystal` | Transparent design |
|
||||
| `emerald` | Modern green palette |
|
||||
| `jade` | Soft jade colors |
|
||||
| `neon` | Bright attention-grabbing |
|
||||
| `onyx` | Dark mode sleek |
|
||||
| `ruby` | Bold ruby accents |
|
||||
| `sapphire` | Elegant blue style |
|
||||
|
||||
[**See all themes with live demos →**](https://php-flasher.io/themes)
|
||||
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
## Notification Libraries
|
||||
|
||||
Need more features? Use popular notification libraries:
|
||||
|
||||
### Toastr
|
||||
|
||||
```bash
|
||||
composer require php-flasher/flasher-toastr-laravel
|
||||
```
|
||||
|
||||
```php
|
||||
flash()->success('Custom message with options.', ['timeout' => 3000, 'position' => 'bottom-left']);
|
||||
toastr()->success('Profile saved!', [
|
||||
'positionClass' => 'toast-bottom-right',
|
||||
'progressBar' => true,
|
||||
]);
|
||||
```
|
||||
|
||||
## Adapters Overview
|
||||
### SweetAlert
|
||||
|
||||
PHPFlasher supports various adapters to integrate seamlessly with different frameworks and frontend libraries. Below is an overview of available adapters:
|
||||
```bash
|
||||
composer require php-flasher/flasher-sweetalert-laravel
|
||||
```
|
||||
|
||||
| Adapter Repository | Description |
|
||||
|-----------------------------------------------------------------------------------------|--------------------------------|
|
||||
| [flasher-laravel](https://github.com/php-flasher/flasher-laravel) | Laravel framework adapter |
|
||||
| [flasher-symfony](https://github.com/php-flasher/flasher-symfony) | Symfony framework adapter |
|
||||
| [flasher-toastr-laravel](https://github.com/php-flasher/flasher-toastr-laravel) | Toastr adapter for Laravel |
|
||||
| [flasher-toastr-symfony](https://github.com/php-flasher/flasher-toastr-symfony) | Toastr adapter for Symfony |
|
||||
| [flasher-noty-laravel](https://github.com/php-flasher/flasher-noty-laravel) | Noty adapter for Laravel |
|
||||
| [flasher-noty-symfony](https://github.com/php-flasher/flasher-noty-symfony) | Noty adapter for Symfony |
|
||||
| [flasher-notyf-laravel](https://github.com/php-flasher/flasher-notyf-laravel) | Notyf adapter for Laravel |
|
||||
| [flasher-notyf-symfony](https://github.com/php-flasher/flasher-notyf-symfony) | Notyf adapter for Symfony |
|
||||
| [flasher-sweetalert-laravel](https://github.com/php-flasher/flasher-sweetalert-laravel) | SweetAlert adapter for Laravel |
|
||||
| [flasher-sweetalert-symfony](https://github.com/php-flasher/flasher-sweetalert-symfony) | SweetAlert adapter for Symfony |
|
||||
```php
|
||||
sweetalert()
|
||||
->showDenyButton()
|
||||
->showCancelButton()
|
||||
->warning('Do you want to save changes?');
|
||||
```
|
||||
|
||||
> **Note:** Each adapter has its own repository. For detailed installation and usage instructions, please refer to the [Official Documentation](https://php-flasher.io).
|
||||
### Noty
|
||||
|
||||
## Official Documentation
|
||||
```bash
|
||||
composer require php-flasher/flasher-noty-laravel
|
||||
```
|
||||
|
||||
Comprehensive documentation for PHPFlasher is available at [https://php-flasher.io](https://php-flasher.io). Here you will find detailed guides, API references, and advanced usage examples to help you get the most out of PHPFlasher.
|
||||
```php
|
||||
noty()->success('Data synchronized!', [
|
||||
'layout' => 'topCenter',
|
||||
'timeout' => 3000,
|
||||
]);
|
||||
```
|
||||
|
||||
## Contributors and sponsors
|
||||
### Notyf
|
||||
|
||||
Join our team of contributors and make a lasting impact on our project!
|
||||
```bash
|
||||
composer require php-flasher/flasher-notyf-laravel
|
||||
```
|
||||
|
||||
We are always looking for passionate individuals who want to contribute their skills and ideas.
|
||||
Whether you're a developer, designer, or simply have a great idea, we welcome your participation and collaboration.
|
||||
```php
|
||||
notyf()->success('Upload complete!', [
|
||||
'dismissible' => true,
|
||||
'ripple' => true,
|
||||
]);
|
||||
```
|
||||
|
||||
Shining stars of our community:
|
||||
---
|
||||
|
||||
<!-- ALL-CONTRIBUTORS-LIST:START -->
|
||||
<!-- prettier-ignore-start -->
|
||||
<!-- markdownlint-disable -->
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://www.linkedin.com/in/younes--ennaji/"><img src="https://avatars.githubusercontent.com/u/10859693?v=4?s=100" width="100px;" alt="Younes ENNAJI"/><br /><sub><b>Younes ENNAJI</b></sub></a><br /><a href="https://github.com/php-flasher/php-flasher/commits?author=yoeunes" title="Code">💻</a> <a href="https://github.com/php-flasher/php-flasher/commits?author=yoeunes" title="Documentation">📖</a> <a href="#maintenance-yoeunes" title="Maintenance">🚧</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/salmayno"><img src="https://avatars.githubusercontent.com/u/27933199?v=4?s=100" width="100px;" alt="Salma Mourad"/><br /><sub><b>Salma Mourad</b></sub></a><br /><a href="#financial-salmayno" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://www.youtube.com/rstacode"><img src="https://avatars.githubusercontent.com/u/35005761?v=4?s=100" width="100px;" alt="Nashwan Abdullah"/><br /><sub><b>Nashwan Abdullah</b></sub></a><br /><a href="#financial-codenashwan" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://darvis.nl/"><img src="https://avatars.githubusercontent.com/u/7394837?v=4?s=100" width="100px;" alt="Arvid de Jong"/><br /><sub><b>Arvid de Jong</b></sub></a><br /><a href="#financial-darviscommerce" title="Financial">💵</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://ashallendesign.co.uk/"><img src="https://avatars.githubusercontent.com/u/39652331?v=4?s=100" width="100px;" alt="Ash Allen"/><br /><sub><b>Ash Allen</b></sub></a><br /><a href="#design-ash-jc-allen" title="Design">🎨</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://about.me/murrant"><img src="https://avatars.githubusercontent.com/u/39462?v=4?s=100" width="100px;" alt="Tony Murray"/><br /><sub><b>Tony Murray</b></sub></a><br /><a href="https://github.com/php-flasher/php-flasher/commits?author=murrant" title="Code">💻</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/n3wborn"><img src="https://avatars.githubusercontent.com/u/10246722?v=4?s=100" width="100px;" alt="Stéphane P"/><br /><sub><b>Stéphane P</b></sub></a><br /><a href="https://github.com/php-flasher/php-flasher/commits?author=n3wborn" title="Documentation">📖</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://www.instagram.com/lucas.maciel_z"><img src="https://avatars.githubusercontent.com/u/80225404?v=4?s=100" width="100px;" alt="Lucas Maciel"/><br /><sub><b>Lucas Maciel</b></sub></a><br /><a href="#design-LucasStorm" title="Design">🎨</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/AhmedGamal"><img src="https://avatars.githubusercontent.com/u/11786167?v=4?s=100" width="100px;" alt="Ahmed Gamal"/><br /><sub><b>Ahmed Gamal</b></sub></a><br /><a href="https://github.com/php-flasher/php-flasher/commits?author=AhmedGamal" title="Code">💻</a> <a href="https://github.com/php-flasher/php-flasher/commits?author=AhmedGamal" title="Documentation">📖</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/BrookeDot"><img src="https://avatars.githubusercontent.com/u/150348?v=4?s=100" width="100px;" alt="Brooke."/><br /><sub><b>Brooke.</b></sub></a><br /><a href="https://github.com/php-flasher/php-flasher/commits?author=BrookeDot" title="Documentation">📖</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
## Livewire Integration
|
||||
|
||||
<!-- markdownlint-restore -->
|
||||
<!-- prettier-ignore-end -->
|
||||
PHPFlasher integrates seamlessly with Laravel Livewire:
|
||||
|
||||
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
||||
```php
|
||||
use Livewire\Attributes\On;
|
||||
|
||||
## Contact
|
||||
class UserProfile extends Component
|
||||
{
|
||||
public function save()
|
||||
{
|
||||
// Save logic...
|
||||
|
||||
PHPFlasher is being actively developed by <a href="https://github.com/yoeunes">yoeunes</a>.
|
||||
You can reach out with questions, bug reports, or feature requests on any of the following:
|
||||
sweetalert()
|
||||
->showDenyButton()
|
||||
->success('Save changes?');
|
||||
}
|
||||
|
||||
- [Github Issues](https://github.com/php-flasher/php-flasher/issues)
|
||||
- [Github](https://github.com/yoeunes)
|
||||
- [Twitter](https://twitter.com/yoeunes)
|
||||
- [Linkedin](https://www.linkedin.com/in/younes--ennaji/)
|
||||
- [Email me directly](mailto:younes.ennaji.pro@gmail.com)
|
||||
#[On('sweetalert:confirmed')]
|
||||
public function onConfirmed(array $payload): void
|
||||
{
|
||||
// User clicked confirm
|
||||
$this->user->save();
|
||||
flash()->success('Profile saved!');
|
||||
}
|
||||
|
||||
#[On('sweetalert:denied')]
|
||||
public function onDenied(array $payload): void
|
||||
{
|
||||
// User clicked deny
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
[**Livewire documentation →**](https://php-flasher.io/livewire)
|
||||
|
||||
---
|
||||
|
||||
## Configuration
|
||||
|
||||
### Laravel
|
||||
|
||||
```php
|
||||
// config/flasher.php
|
||||
return [
|
||||
'default' => 'flasher',
|
||||
'themes' => [
|
||||
'flasher' => [
|
||||
'options' => [
|
||||
'timeout' => 5000,
|
||||
'position' => 'top-right',
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
```
|
||||
|
||||
### Symfony
|
||||
|
||||
```yaml
|
||||
# config/packages/flasher.yaml
|
||||
flasher:
|
||||
default: flasher
|
||||
themes:
|
||||
flasher:
|
||||
options:
|
||||
timeout: 5000
|
||||
position: top-right
|
||||
```
|
||||
|
||||
### Common Options
|
||||
|
||||
| Option | Type | Default | Description |
|
||||
|--------|------|---------|-------------|
|
||||
| `timeout` | int | `5000` | Auto-dismiss delay in ms (0 = sticky) |
|
||||
| `position` | string | `top-right` | `top-right`, `top-left`, `bottom-right`, `bottom-left`, `top-center`, `bottom-center` |
|
||||
| `closeButton` | bool | `true` | Show close button |
|
||||
| `progressBar` | bool | `true` | Show timeout progress bar |
|
||||
| `rtl` | bool | `false` | Right-to-left text direction |
|
||||
| `escapeHtml` | bool | `true` | Escape HTML in messages |
|
||||
|
||||
---
|
||||
|
||||
## Requirements
|
||||
|
||||
| Requirement | Version |
|
||||
|-------------|---------|
|
||||
| PHP | >= 8.2 |
|
||||
| Laravel | >= 11.0 |
|
||||
| Symfony | >= 7.0 |
|
||||
|
||||
---
|
||||
|
||||
## Documentation
|
||||
|
||||
For complete documentation, visit **[php-flasher.io](https://php-flasher.io)**
|
||||
|
||||
- [Installation Guide](https://php-flasher.io/installation)
|
||||
- [Laravel Integration](https://php-flasher.io/laravel)
|
||||
- [Symfony Integration](https://php-flasher.io/symfony)
|
||||
- [Livewire Integration](https://php-flasher.io/livewire)
|
||||
- [Inertia.js Integration](https://php-flasher.io/inertia)
|
||||
- [Themes Gallery](https://php-flasher.io/themes)
|
||||
- [JavaScript Usage](https://php-flasher.io/javascript)
|
||||
|
||||
---
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are welcome! Please feel free to submit a [Pull Request](https://github.com/php-flasher/php-flasher/pulls).
|
||||
|
||||
## Contributors
|
||||
|
||||
<a href="https://github.com/php-flasher/php-flasher/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=php-flasher/php-flasher" alt="Contributors" />
|
||||
</a>
|
||||
|
||||
---
|
||||
|
||||
## Support the Project
|
||||
|
||||
If PHPFlasher helps you build better applications, please consider:
|
||||
|
||||
- **[Star this repository](https://github.com/php-flasher/php-flasher)** to show your support
|
||||
- **[Report bugs](https://github.com/php-flasher/php-flasher/issues)** to help improve the library
|
||||
- **[Share on Twitter](https://twitter.com/intent/tweet?text=Check%20out%20PHPFlasher%20-%20beautiful%20flash%20notifications%20for%20PHP!&url=https://github.com/php-flasher/php-flasher)** to spread the word
|
||||
|
||||
---
|
||||
|
||||
## License
|
||||
|
||||
PHPFlasher is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT).
|
||||
PHPFlasher is open-source software licensed under the [MIT license](LICENSE).
|
||||
|
||||
<p align="center"> <b>Made with ❤️ by <a href="https://www.linkedin.com/in/younes--ennaji/">Younes ENNAJI</a> </b> </p>
|
||||
<p align="center">
|
||||
<br>
|
||||
<strong>Made with ❤️ by <a href="https://github.com/yoeunes">Younes ENNAJI</a></strong>
|
||||
<br><br>
|
||||
<a href="https://github.com/php-flasher/php-flasher/stargazers">⭐ Star if you find this useful!</a>
|
||||
</p>
|
||||
|
||||
Executable
+675
@@ -0,0 +1,675 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# =========================================================================
|
||||
# Build System for PHP-Flasher
|
||||
# =========================================================================
|
||||
#
|
||||
# This script provides an elegant build process for PHP-Flasher assets
|
||||
# with comprehensive reporting and flexible configuration options.
|
||||
#
|
||||
# Author: Younes ENNAJI
|
||||
# =========================================================================
|
||||
|
||||
# Strict error handling
|
||||
set -o pipefail
|
||||
|
||||
# =========================================================================
|
||||
# CONSTANTS AND CONFIGURATION
|
||||
# =========================================================================
|
||||
|
||||
# Colors and styles
|
||||
readonly RESET='\033[0m'
|
||||
readonly BOLD='\033[1m'
|
||||
readonly DIM='\033[2m'
|
||||
readonly UNDERLINE='\033[4m'
|
||||
readonly BLUE='\033[34m'
|
||||
readonly GREEN='\033[32m'
|
||||
readonly RED='\033[31m'
|
||||
readonly YELLOW='\033[33m'
|
||||
readonly CYAN='\033[36m'
|
||||
readonly MAGENTA='\033[35m'
|
||||
readonly WHITE='\033[37m'
|
||||
|
||||
# Emoji indicators
|
||||
readonly ROCKET="🚀"
|
||||
readonly PACKAGE="📦"
|
||||
readonly CHECK="✓"
|
||||
readonly ERROR="❌"
|
||||
readonly WARNING="⚠️"
|
||||
readonly HAMMER="🏗️"
|
||||
readonly CHART="📊"
|
||||
readonly SPARKLES="✨"
|
||||
readonly HOURGLASS="⏳"
|
||||
readonly PALETTE="🎨"
|
||||
|
||||
# File paths
|
||||
readonly SRC_DIR="src"
|
||||
readonly PRIME_PATH="${SRC_DIR}/Prime/Resources"
|
||||
readonly TEMP_DIR="/tmp/php-flasher-build-$$"
|
||||
readonly BUILD_LOG="${TEMP_DIR}/build.log"
|
||||
readonly SIZE_DATA="${TEMP_DIR}/sizes.data"
|
||||
|
||||
# Default configuration
|
||||
VERBOSE=false
|
||||
WATCH_MODE=false
|
||||
THEME_ONLY=false
|
||||
MODULE_ONLY=false
|
||||
ANALYZE=false
|
||||
DEEP_ANALYZE=false
|
||||
SKIP_CLEAR=false
|
||||
NODE_ENV="production"
|
||||
|
||||
# =========================================================================
|
||||
# UTILITY FUNCTIONS
|
||||
# =========================================================================
|
||||
|
||||
cleanup() {
|
||||
# Clean up temporary files when the script exits
|
||||
rm -rf "${TEMP_DIR}" 2>/dev/null
|
||||
}
|
||||
|
||||
trap cleanup EXIT
|
||||
|
||||
mkdir -p "${TEMP_DIR}"
|
||||
|
||||
print_header() {
|
||||
echo -e "\n${BOLD}Date : ${RESET}${CYAN}$(date -u '+%Y-%m-%d %H:%M:%S') UTC${RESET}"
|
||||
echo -e "${BOLD}User : ${RESET}${MAGENTA}$(whoami)${RESET}"
|
||||
echo -e "${BOLD}Branch : ${RESET}${GREEN}$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "unknown")${RESET}"
|
||||
echo -e "${BOLD}Directory : ${RESET}${BLUE}$(pwd)${RESET}"
|
||||
|
||||
if [ "$NODE_ENV" != "production" ]; then
|
||||
echo -e "${BOLD}Mode : ${RESET}${YELLOW}${NODE_ENV}${RESET}"
|
||||
fi
|
||||
|
||||
if [ "$WATCH_MODE" = true ]; then
|
||||
echo -e "${BOLD}Watch : ${RESET}${CYAN}enabled${RESET}"
|
||||
fi
|
||||
|
||||
if [ "$THEME_ONLY" = true ]; then
|
||||
echo -e "${BOLD}Scope : ${RESET}${MAGENTA}themes only${RESET}"
|
||||
elif [ "$MODULE_ONLY" = true ]; then
|
||||
echo -e "${BOLD}Scope : ${RESET}${MAGENTA}modules only${RESET}"
|
||||
fi
|
||||
|
||||
echo
|
||||
}
|
||||
|
||||
print_section() {
|
||||
echo -e "\n${BOLD}${CYAN}┌─ $1 ${2:-}${RESET}"
|
||||
}
|
||||
|
||||
success_msg() {
|
||||
echo -e "${GREEN}${CHECK} $*${RESET}"
|
||||
}
|
||||
|
||||
error_msg() {
|
||||
echo -e "${RED}${ERROR} $*${RESET}"
|
||||
}
|
||||
|
||||
warning_msg() {
|
||||
echo -e "${YELLOW}${WARNING} $*${RESET}"
|
||||
}
|
||||
|
||||
info_msg() {
|
||||
echo -e "${BLUE}${HOURGLASS} $*${RESET}"
|
||||
}
|
||||
|
||||
print_usage() {
|
||||
echo -e "${BOLD}Usage:${RESET} $0 [options]"
|
||||
echo
|
||||
echo -e "${BOLD}Options:${RESET}"
|
||||
echo -e " ${GREEN}-h, --help${RESET} Show this help message"
|
||||
echo -e " ${GREEN}-v, --verbose${RESET} Display detailed build output"
|
||||
echo -e " ${GREEN}-w, --watch${RESET} Run in watch mode"
|
||||
echo -e " ${GREEN}-d, --development${RESET} Build in development mode (unminified)"
|
||||
echo -e " ${GREEN}-t, --themes-only${RESET} Build only themes"
|
||||
echo -e " ${GREEN}-m, --modules-only${RESET} Build only modules (core and plugins)"
|
||||
echo -e " ${GREEN}-a, --analyze${RESET} Show detailed size analysis in table format"
|
||||
echo -e " ${GREEN}-D, --deep-analyze${RESET} Perform deep analysis of files (checksums, content inspection)"
|
||||
echo -e " ${GREEN}--skip-clear${RESET} Skip clearing output directories"
|
||||
echo
|
||||
}
|
||||
|
||||
parse_args() {
|
||||
while [ "$#" -gt 0 ]; do
|
||||
case "$1" in
|
||||
-h|--help)
|
||||
print_usage
|
||||
exit 0
|
||||
;;
|
||||
-v|--verbose)
|
||||
VERBOSE=true
|
||||
;;
|
||||
-w|--watch)
|
||||
WATCH_MODE=true
|
||||
NODE_ENV="development"
|
||||
;;
|
||||
-d|--development)
|
||||
NODE_ENV="development"
|
||||
;;
|
||||
-t|--themes-only)
|
||||
THEME_ONLY=true
|
||||
;;
|
||||
-m|--modules-only)
|
||||
MODULE_ONLY=true
|
||||
;;
|
||||
-a|--analyze)
|
||||
ANALYZE=true
|
||||
;;
|
||||
-D|--deep-analyze)
|
||||
ANALYZE=true
|
||||
DEEP_ANALYZE=true
|
||||
;;
|
||||
--skip-clear)
|
||||
SKIP_CLEAR=true
|
||||
;;
|
||||
*)
|
||||
warning_msg "Unknown option: $1"
|
||||
print_usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
# Validate conflicting options
|
||||
if [ "$THEME_ONLY" = true ] && [ "$MODULE_ONLY" = true ]; then
|
||||
error_msg "Cannot specify both --themes-only and --modules-only"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Configure build mode
|
||||
if [ "$WATCH_MODE" = true ]; then
|
||||
ROLLUP_ARGS="-c -w"
|
||||
else
|
||||
ROLLUP_ARGS="-c"
|
||||
fi
|
||||
|
||||
# When analyzing, we turn off verbosity for rollup
|
||||
if [ "$ANALYZE" = true ]; then
|
||||
export FILESIZE_SILENT=true
|
||||
fi
|
||||
}
|
||||
|
||||
# =========================================================================
|
||||
# BUILD FUNCTIONS
|
||||
# =========================================================================
|
||||
|
||||
get_size_info() {
|
||||
local file="$1"
|
||||
# Get precise byte count for more accurate comparison
|
||||
local bytes=$(wc -c < "$file")
|
||||
local size=$(du -h "$file" | awk '{print $1}')
|
||||
local gzip=$(gzip -c "$file" | wc -c | numfmt --to=iec --format="%.1f")
|
||||
local brotli_size=$(brotli -c "$file" 2>/dev/null | wc -c | numfmt --to=iec --format="%.1f" || echo "N/A")
|
||||
|
||||
echo "$size|$gzip|$bytes|$brotli_size"
|
||||
}
|
||||
|
||||
get_file_hash() {
|
||||
local file="$1"
|
||||
if command -v sha256sum &> /dev/null; then
|
||||
sha256sum "$file" | awk '{print $1}'
|
||||
elif command -v shasum &> /dev/null; then
|
||||
shasum -a 256 "$file" | awk '{print $1}'
|
||||
else
|
||||
echo "HASH_UNAVAILABLE"
|
||||
fi
|
||||
}
|
||||
|
||||
analyze_file_content() {
|
||||
local file="$1"
|
||||
local filename=$(basename "$file")
|
||||
local dir="${TEMP_DIR}/analysis/$(dirname "$file" | sed 's/\//_/g')"
|
||||
mkdir -p "$dir"
|
||||
|
||||
# Get first 10 lines for a quick look
|
||||
head -n 10 "$file" > "${dir}/${filename}.head"
|
||||
|
||||
# Get hash for exact comparison
|
||||
local hash=$(get_file_hash "$file")
|
||||
echo "$hash" > "${dir}/${filename}.hash"
|
||||
|
||||
# For CSS/JS, try to determine if it's minified
|
||||
if [[ "$file" == *.css || "$file" == *.js ]]; then
|
||||
# Count semicolons to help identify if minified
|
||||
local semicolons=$(grep -o ";" "$file" | wc -l)
|
||||
# Count newlines
|
||||
local newlines=$(grep -c $'\n' "$file")
|
||||
|
||||
# Simple heuristic: if few newlines relative to semicolons, likely minified
|
||||
if [ "$newlines" -lt 10 ] || [ "$semicolons" -gt "$((newlines * 5))" ]; then
|
||||
echo "MINIFIED:YES semicolons:$semicolons newlines:$newlines" > "${dir}/${filename}.analysis"
|
||||
else
|
||||
echo "MINIFIED:NO semicolons:$semicolons newlines:$newlines" > "${dir}/${filename}.analysis"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "$hash"
|
||||
}
|
||||
|
||||
collect_build_statistics() {
|
||||
local modules_count=0
|
||||
local themes_count=0
|
||||
declare -a theme_names=()
|
||||
local unique_css_hashes=0
|
||||
local unique_js_hashes=0
|
||||
declare -A css_hashes=()
|
||||
declare -A js_hashes=()
|
||||
|
||||
# Create temporary directory for data
|
||||
mkdir -p "${TEMP_DIR}/modules"
|
||||
mkdir -p "${TEMP_DIR}/themes"
|
||||
mkdir -p "${TEMP_DIR}/analysis"
|
||||
|
||||
echo "DEBUG: Looking for modules and themes..." >> "${BUILD_LOG}"
|
||||
|
||||
# Check for core flasher module first
|
||||
if [ -f "${PRIME_PATH}/dist/flasher.min.js" ]; then
|
||||
local size_info=$(get_size_info "${PRIME_PATH}/dist/flasher.min.js")
|
||||
local hash="N/A"
|
||||
if [ "$DEEP_ANALYZE" = true ]; then
|
||||
hash=$(analyze_file_content "${PRIME_PATH}/dist/flasher.min.js")
|
||||
js_hashes["$hash"]=1
|
||||
((unique_js_hashes++))
|
||||
fi
|
||||
echo "flasher:$size_info:$hash" >> "${TEMP_DIR}/modules/data"
|
||||
((modules_count++))
|
||||
fi
|
||||
|
||||
# Collect module statistics - FIXED to avoid subshell issue
|
||||
# Store filenames to process in a temporary file
|
||||
find ${SRC_DIR}/*/Prime/Resources/dist -name "*.min.js" | grep -v themes > "${TEMP_DIR}/module_files.txt" 2>/dev/null
|
||||
|
||||
# Process each module file
|
||||
while IFS= read -r file; do
|
||||
local module=$(basename "$file" .min.js)
|
||||
local size_info=$(get_size_info "$file")
|
||||
local hash="N/A"
|
||||
if [ "$DEEP_ANALYZE" = true ]; then
|
||||
hash=$(analyze_file_content "$file")
|
||||
js_hashes["$hash"]=1
|
||||
((unique_js_hashes++))
|
||||
fi
|
||||
echo "$module:$size_info:$hash" >> "${TEMP_DIR}/modules/data"
|
||||
((modules_count++))
|
||||
echo "DEBUG: Found module: $module in $file (${size_info})" >> "${BUILD_LOG}"
|
||||
done < "${TEMP_DIR}/module_files.txt"
|
||||
|
||||
# Collect theme statistics - FIXED to avoid subshell issue
|
||||
if [ -d "${PRIME_PATH}/dist/themes" ]; then
|
||||
# Store theme files in a temporary file
|
||||
find ${PRIME_PATH}/dist/themes -name "*.min.js" > "${TEMP_DIR}/theme_files.txt" 2>/dev/null
|
||||
|
||||
# Process each theme file
|
||||
while IFS= read -r file; do
|
||||
local theme=$(basename "$(dirname "$file")")
|
||||
local size_info=$(get_size_info "$file")
|
||||
local js_hash="N/A"
|
||||
local css_hash="N/A"
|
||||
|
||||
# Also get the CSS file size and analyze it
|
||||
local css_file="${PRIME_PATH}/dist/themes/${theme}/${theme}.min.css"
|
||||
local css_size_info="N/A"
|
||||
if [ -f "$css_file" ]; then
|
||||
css_size_info=$(get_size_info "$css_file")
|
||||
|
||||
if [ "$DEEP_ANALYZE" = true ]; then
|
||||
css_hash=$(analyze_file_content "$css_file")
|
||||
if [ -z "${css_hashes[$css_hash]}" ]; then
|
||||
css_hashes["$css_hash"]=1
|
||||
((unique_css_hashes++))
|
||||
else
|
||||
css_hashes["$css_hash"]=$((css_hashes["$css_hash"] + 1))
|
||||
fi
|
||||
|
||||
js_hash=$(analyze_file_content "$file")
|
||||
if [ -z "${js_hashes[$js_hash]}" ]; then
|
||||
js_hashes["$js_hash"]=1
|
||||
else
|
||||
js_hashes["$js_hash"]=$((js_hashes["$js_hash"] + 1))
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "DEBUG: Theme $theme JS: $size_info, CSS: $css_size_info" >> "${BUILD_LOG}"
|
||||
else
|
||||
echo "DEBUG: No CSS file found for theme $theme" >> "${BUILD_LOG}"
|
||||
fi
|
||||
|
||||
echo "$theme:$size_info:$js_hash:$css_size_info:$css_hash" >> "${TEMP_DIR}/themes/data"
|
||||
theme_names+=("$theme")
|
||||
((themes_count++))
|
||||
done < "${TEMP_DIR}/theme_files.txt"
|
||||
|
||||
# Sort theme names alphabetically
|
||||
if [ ${#theme_names[@]} -gt 0 ]; then
|
||||
printf "%s\n" "${theme_names[@]}" | sort > "${TEMP_DIR}/theme_names"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Store counts for summary
|
||||
echo "$modules_count" > "${TEMP_DIR}/modules_count"
|
||||
echo "$themes_count" > "${TEMP_DIR}/themes_count"
|
||||
echo "$unique_js_hashes" > "${TEMP_DIR}/unique_js_hashes"
|
||||
echo "$unique_css_hashes" > "${TEMP_DIR}/unique_css_hashes"
|
||||
|
||||
# Write hash statistics if deep analysis was enabled
|
||||
if [ "$DEEP_ANALYZE" = true ]; then
|
||||
echo "JS Hash Distribution:" > "${TEMP_DIR}/hash_stats.txt"
|
||||
for hash in "${!js_hashes[@]}"; do
|
||||
echo " $hash: ${js_hashes[$hash]} files" >> "${TEMP_DIR}/hash_stats.txt"
|
||||
done
|
||||
|
||||
echo -e "\nCSS Hash Distribution:" >> "${TEMP_DIR}/hash_stats.txt"
|
||||
for hash in "${!css_hashes[@]}"; do
|
||||
echo " $hash: ${css_hashes[$hash]} files" >> "${TEMP_DIR}/hash_stats.txt"
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
run_build() {
|
||||
print_section "Starting Build Process" "${HAMMER}"
|
||||
|
||||
info_msg "Environment: ${NODE_ENV}"
|
||||
info_msg "Building PHP-Flasher assets..."
|
||||
|
||||
# Set environment variables
|
||||
export NODE_ENV="$NODE_ENV"
|
||||
export ANALYZE="$ANALYZE"
|
||||
export DEEP_ANALYZE="$DEEP_ANALYZE"
|
||||
|
||||
# Determine which parts to build based on flags
|
||||
local rollup_args="$ROLLUP_ARGS"
|
||||
if [ "$THEME_ONLY" = true ]; then
|
||||
info_msg "Building themes only"
|
||||
# Here we'd need to extend rollup to support theme-only builds
|
||||
# For now, we'll complete the full build
|
||||
elif [ "$MODULE_ONLY" = true ]; then
|
||||
info_msg "Building modules only"
|
||||
# Similarly, we'd need to extend rollup
|
||||
fi
|
||||
|
||||
# Execute rollup with appropriate flags
|
||||
if [ "$VERBOSE" = true ]; then
|
||||
if npx rollup $rollup_args; then
|
||||
success_msg "Build process completed"
|
||||
return 0
|
||||
else
|
||||
error_msg "Build process failed"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
# Capture output for non-verbose mode
|
||||
if npx rollup $rollup_args > "$BUILD_LOG" 2>&1; then
|
||||
success_msg "Build process completed"
|
||||
return 0
|
||||
else
|
||||
error_msg "Build process failed"
|
||||
cat "$BUILD_LOG"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# =========================================================================
|
||||
# REPORTING FUNCTIONS
|
||||
# =========================================================================
|
||||
|
||||
print_size_table() {
|
||||
local title="$1"
|
||||
local data_file="$2"
|
||||
local max_name_len=20
|
||||
|
||||
if [ ! -f "$data_file" ] || [ ! -s "$data_file" ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
echo -e "\n${BOLD}${WHITE}${title}${RESET}\n"
|
||||
|
||||
# Print table header with or without hashes based on deep analysis
|
||||
if [ "$DEEP_ANALYZE" = true ]; then
|
||||
printf "${BOLD}%-${max_name_len}s %-10s %-10s %-10s %-10s${RESET}\n" "Component" "Size" "Gzip" "Bytes" "Hash"
|
||||
else
|
||||
printf "${BOLD}%-${max_name_len}s %-10s %-10s %-10s${RESET}\n" "Component" "Size" "Gzip" "Bytes"
|
||||
fi
|
||||
|
||||
echo -e "${DIM}$(printf '%.0s─' {1..70})${RESET}"
|
||||
|
||||
# Print table rows
|
||||
while IFS=: read -r line; do
|
||||
# Split the line into fields
|
||||
local fields=()
|
||||
while IFS=: read -ra parts; do
|
||||
fields=("${parts[@]}")
|
||||
done <<< "$line"
|
||||
|
||||
local name="${fields[0]}"
|
||||
local size_data="${fields[1]}"
|
||||
local hash="N/A"
|
||||
if [ "${#fields[@]}" -gt 2 ]; then
|
||||
hash="${fields[2]}"
|
||||
fi
|
||||
|
||||
IFS='|' read -r size gzip bytes brotli <<< "$size_data"
|
||||
|
||||
if [ "$DEEP_ANALYZE" = true ]; then
|
||||
printf "%-${max_name_len}s ${GREEN}%-10s${RESET} ${BLUE}%-10s${RESET} ${YELLOW}%-10s${RESET} ${DIM}%.8s${RESET}\n" \
|
||||
"$name" "$size" "$gzip" "$bytes" "$hash"
|
||||
else
|
||||
printf "%-${max_name_len}s ${GREEN}%-10s${RESET} ${BLUE}%-10s${RESET} ${YELLOW}%-10s${RESET}\n" \
|
||||
"$name" "$size" "$gzip" "$bytes"
|
||||
fi
|
||||
done < "$data_file"
|
||||
}
|
||||
|
||||
print_theme_table() {
|
||||
local data_file="$1"
|
||||
local max_name_len=15
|
||||
|
||||
if [ ! -f "$data_file" ] || [ ! -s "$data_file" ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
echo -e "\n${BOLD}${WHITE}Theme Sizes${RESET}\n"
|
||||
|
||||
# Print table header
|
||||
printf "${BOLD}%-${max_name_len}s %-10s %-10s %-10s %-10s${RESET}\n" "Theme" "JS Size" "CSS Size" "JS Bytes" "CSS Bytes"
|
||||
echo -e "${DIM}$(printf '%.0s─' {1..70})${RESET}"
|
||||
|
||||
# Print table rows
|
||||
while IFS=: read -r line; do
|
||||
# Split the line into fields
|
||||
local fields=()
|
||||
while IFS=: read -ra parts; do
|
||||
fields=("${parts[@]}")
|
||||
done <<< "$line"
|
||||
|
||||
local name="${fields[0]}"
|
||||
local js_size_data="${fields[1]}"
|
||||
local js_hash="N/A"
|
||||
local css_size_data="N/A"
|
||||
local css_hash="N/A"
|
||||
|
||||
if [ "${#fields[@]}" -gt 2 ]; then
|
||||
js_hash="${fields[2]}"
|
||||
fi
|
||||
|
||||
if [ "${#fields[@]}" -gt 3 ]; then
|
||||
css_size_data="${fields[3]}"
|
||||
fi
|
||||
|
||||
if [ "${#fields[@]}" -gt 4 ]; then
|
||||
css_hash="${fields[4]}"
|
||||
fi
|
||||
|
||||
IFS='|' read -r js_size js_gzip js_bytes js_brotli <<< "$js_size_data"
|
||||
|
||||
local css_size="N/A"
|
||||
local css_bytes="N/A"
|
||||
|
||||
if [ "$css_size_data" != "N/A" ]; then
|
||||
IFS='|' read -r css_size css_gzip css_bytes css_brotli <<< "$css_size_data"
|
||||
fi
|
||||
|
||||
printf "%-${max_name_len}s ${GREEN}%-10s${RESET} ${MAGENTA}%-10s${RESET} ${YELLOW}%-10s${RESET} ${BLUE}%-10s${RESET}\n" \
|
||||
"$name" "$js_size" "$css_size" "$js_bytes" "$css_bytes"
|
||||
done < "$data_file"
|
||||
}
|
||||
|
||||
print_theme_grid() {
|
||||
local theme_names_file="$1"
|
||||
if [ ! -f "$theme_names_file" ] || [ ! -s "$theme_names_file" ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
echo -e "\n${BOLD}${MAGENTA}${PALETTE} Themes:${RESET}"
|
||||
|
||||
# Define grid parameters
|
||||
local columns=3
|
||||
local max_width=15
|
||||
local count=0
|
||||
|
||||
# Print themes in a grid
|
||||
while read -r theme; do
|
||||
if [ $((count % columns)) -eq 0 ]; then
|
||||
echo -ne " "
|
||||
fi
|
||||
|
||||
printf "• %-${max_width}s" "$theme"
|
||||
count=$((count + 1))
|
||||
|
||||
if [ $((count % columns)) -eq 0 ]; then
|
||||
echo
|
||||
fi
|
||||
done < "$theme_names_file"
|
||||
|
||||
# Add a newline if the last row wasn't complete
|
||||
if [ $((count % columns)) -ne 0 ]; then
|
||||
echo
|
||||
fi
|
||||
}
|
||||
|
||||
print_deep_analysis() {
|
||||
if [ ! -d "${TEMP_DIR}/analysis" ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
local unique_js=0
|
||||
local unique_css=0
|
||||
|
||||
if [ -f "${TEMP_DIR}/unique_js_hashes" ]; then
|
||||
unique_js=$(cat "${TEMP_DIR}/unique_js_hashes")
|
||||
fi
|
||||
|
||||
if [ -f "${TEMP_DIR}/unique_css_hashes" ]; then
|
||||
unique_css=$(cat "${TEMP_DIR}/unique_css_hashes")
|
||||
fi
|
||||
|
||||
echo -e "\n${BOLD}${WHITE}Deep File Analysis${RESET}"
|
||||
echo -e "${DIM}$(printf '%.0s─' {1..50})${RESET}"
|
||||
|
||||
echo -e "Unique JavaScript files: ${YELLOW}${unique_js}${RESET}"
|
||||
echo -e "Unique CSS files: ${MAGENTA}${unique_css}${RESET}"
|
||||
|
||||
if [ -f "${TEMP_DIR}/hash_stats.txt" ]; then
|
||||
echo -e "\n${BOLD}Hash Distribution:${RESET}"
|
||||
local top_5=$(head -n 10 "${TEMP_DIR}/hash_stats.txt")
|
||||
echo -e "${DIM}$top_5${RESET}"
|
||||
echo -e "${DIM}(See ${TEMP_DIR}/hash_stats.txt for full details)${RESET}"
|
||||
fi
|
||||
}
|
||||
|
||||
print_summary() {
|
||||
local success=$1
|
||||
local duration=$2
|
||||
|
||||
# Read statistics
|
||||
local modules_count=0
|
||||
local themes_count=0
|
||||
|
||||
if [ -f "${TEMP_DIR}/modules_count" ]; then
|
||||
modules_count=$(cat "${TEMP_DIR}/modules_count")
|
||||
fi
|
||||
|
||||
if [ -f "${TEMP_DIR}/themes_count" ]; then
|
||||
themes_count=$(cat "${TEMP_DIR}/themes_count")
|
||||
fi
|
||||
|
||||
# Print summary header
|
||||
echo -e "\n${BOLD}${PACKAGE} Build Summary${RESET}"
|
||||
echo -e "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
|
||||
# Print statistics
|
||||
if [ "$MODULE_ONLY" = false ]; then
|
||||
echo -e "${CHECK} Modules/Plugins: ${BOLD}${CYAN}${modules_count}${RESET}"
|
||||
fi
|
||||
|
||||
if [ "$THEME_ONLY" = false ]; then
|
||||
echo -e "${CHECK} Themes: ${BOLD}${MAGENTA}${themes_count}${RESET}"
|
||||
fi
|
||||
|
||||
echo -e "${CHECK} Build completed in ${BOLD}${YELLOW}${duration}s${RESET}"
|
||||
|
||||
# Print theme names if available
|
||||
if [ -f "${TEMP_DIR}/theme_names" ]; then
|
||||
print_theme_grid "${TEMP_DIR}/theme_names"
|
||||
fi
|
||||
|
||||
# Show size analysis if requested
|
||||
if [ "$ANALYZE" = true ]; then
|
||||
echo -e "\n${BOLD}${CHART} Size Analysis:${RESET}"
|
||||
print_size_table "Module Sizes" "${TEMP_DIR}/modules/data"
|
||||
|
||||
if [ "$DEEP_ANALYZE" = true ]; then
|
||||
print_theme_table "${TEMP_DIR}/themes/data"
|
||||
print_deep_analysis
|
||||
else
|
||||
print_size_table "Theme Sizes" "${TEMP_DIR}/themes/data"
|
||||
fi
|
||||
|
||||
# Add option to view detailed logs
|
||||
echo -e "\nFor detailed build info, run: ${CYAN}cat $BUILD_LOG${RESET}"
|
||||
echo -e "Temporary files at: ${CYAN}${TEMP_DIR}${RESET}"
|
||||
fi
|
||||
}
|
||||
|
||||
# =========================================================================
|
||||
# MAIN EXECUTION
|
||||
# =========================================================================
|
||||
|
||||
main() {
|
||||
local start_time=$(date +%s)
|
||||
local build_success=true
|
||||
|
||||
# Parse command-line arguments
|
||||
parse_args "$@"
|
||||
|
||||
# Show header
|
||||
print_header
|
||||
|
||||
# Run the build process
|
||||
run_build || build_success=false
|
||||
|
||||
# Only collect statistics if build was successful and not in watch mode
|
||||
if [ "$WATCH_MODE" = false ] && [ "$build_success" = true ]; then
|
||||
if [ "$ANALYZE" = true ] || [ ! -t 1 ]; then
|
||||
print_section "Analyzing Build Output" "${CHART}"
|
||||
fi
|
||||
collect_build_statistics
|
||||
fi
|
||||
|
||||
# Print summary (unless in watch mode)
|
||||
if [ "$WATCH_MODE" = false ]; then
|
||||
local end_time=$(date +%s)
|
||||
local duration=$((end_time - start_time))
|
||||
|
||||
print_summary "$build_success" "$duration"
|
||||
fi
|
||||
|
||||
# Exit with appropriate code
|
||||
[ "$build_success" = true ] && exit 0 || exit 1
|
||||
}
|
||||
|
||||
# Execute main function with all arguments
|
||||
main "$@"
|
||||
@@ -0,0 +1,199 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
set -o pipefail
|
||||
|
||||
# Colors and styles
|
||||
readonly RESET='\033[0m'
|
||||
readonly BOLD='\033[1m'
|
||||
readonly BLUE='\033[34m'
|
||||
readonly GREEN='\033[32m'
|
||||
readonly RED='\033[31m'
|
||||
readonly YELLOW='\033[33m'
|
||||
|
||||
# Emojis
|
||||
readonly ROCKET="🚀"
|
||||
readonly UPDATE="🔄"
|
||||
readonly PACKAGE="📦"
|
||||
readonly SUCCESS="✨"
|
||||
readonly ERROR="❌"
|
||||
readonly WARNING="⚠️"
|
||||
readonly CHECK="✓"
|
||||
|
||||
# Header
|
||||
print_header() {
|
||||
echo -e "\n${BOLD}${BLUE}╭──────────────────────────────────────────╮${RESET}"
|
||||
echo -e "${BOLD}${BLUE}│ ${ROCKET} PHP-Flasher Version ${ROCKET} │${RESET}"
|
||||
echo -e "${BOLD}${BLUE}╰──────────────────────────────────────────╯${RESET}\n"
|
||||
echo -e " Date : $(date -u '+%Y-%m-%d %H:%M:%S') UTC"
|
||||
echo -e " User : $(whoami)"
|
||||
echo -e " Directory: $(pwd)\n"
|
||||
}
|
||||
|
||||
# Version validation
|
||||
validate_version() {
|
||||
local version=$1
|
||||
if [[ ! $version =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||||
echo -e "\n${RED}${ERROR} Invalid version format: $version${RESET}"
|
||||
echo -e " Version must be in format X.Y.Z (e.g., 2.1.6)\n"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Get current version from Flasher class
|
||||
get_current_version() {
|
||||
local file="src/Prime/Flasher.php"
|
||||
if [ -f "$file" ]; then
|
||||
local version=$(grep -o "const VERSION = '[0-9]\+\.[0-9]\+\.[0-9]\+'" "$file" | grep -o "[0-9]\+\.[0-9]\+\.[0-9]\+")
|
||||
echo "$version"
|
||||
else
|
||||
echo -e "${RED}${ERROR} Flasher.php not found in src/Prime/Flasher.php${RESET}"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Update composer.json file
|
||||
update_composer_file() {
|
||||
local file=$1
|
||||
local current_version=$2
|
||||
local new_version=$3
|
||||
|
||||
# Create a temporary file
|
||||
local tmp_file="${file}.tmp"
|
||||
|
||||
# Use jq with 4-space indentation
|
||||
if command -v jq >/dev/null 2>&1; then
|
||||
jq --indent 4 --arg cv "^${current_version}" --arg nv "^${new_version}" '
|
||||
walk(
|
||||
if type == "object" and has("require") then
|
||||
.require |= with_entries(
|
||||
if .key | startswith("php-flasher/") then
|
||||
.value = $nv
|
||||
else
|
||||
.
|
||||
end
|
||||
)
|
||||
else
|
||||
.
|
||||
end
|
||||
)
|
||||
' "$file" > "$tmp_file"
|
||||
else
|
||||
# Fallback to sed for simple replacement
|
||||
sed -E "s/\"php-flasher\/[^\"]+\": \"\\^${current_version}\"/\"\\0\": \"^${new_version}\"/" "$file" > "$tmp_file"
|
||||
fi
|
||||
|
||||
# Check if the temporary file exists and has content
|
||||
if [ -s "$tmp_file" ]; then
|
||||
mv "$tmp_file" "$file"
|
||||
echo " ${CHECK} Updated $file"
|
||||
else
|
||||
echo " ${WARNING} Failed to update $file"
|
||||
rm -f "$tmp_file"
|
||||
fi
|
||||
}
|
||||
|
||||
# Update package.json file
|
||||
update_package_file() {
|
||||
local file=$1
|
||||
local current_version=$2
|
||||
local new_version=$3
|
||||
|
||||
# Create a temporary file
|
||||
local tmp_file="${file}.tmp"
|
||||
|
||||
# Use jq with 4-space indentation
|
||||
if command -v jq >/dev/null 2>&1; then
|
||||
jq --indent 4 --arg cv "^${current_version}" --arg nv "^${new_version}" --arg v "${new_version}" '
|
||||
.version = $v |
|
||||
if has("peerDependencies") then
|
||||
.peerDependencies |= with_entries(
|
||||
if .key | startswith("@flasher/") then
|
||||
.value = $nv
|
||||
else
|
||||
.
|
||||
end
|
||||
)
|
||||
else
|
||||
.
|
||||
end |
|
||||
if has("dependencies") then
|
||||
.dependencies |= with_entries(
|
||||
if .key | startswith("@flasher/") then
|
||||
.value = $nv
|
||||
else
|
||||
.
|
||||
end
|
||||
)
|
||||
else
|
||||
.
|
||||
end
|
||||
' "$file" > "$tmp_file"
|
||||
else
|
||||
# Fallback to sed for simple replacement
|
||||
sed -E -e "s/\"version\": \"${current_version}\"/\"version\": \"${new_version}\"/" \
|
||||
-e "s/\"@flasher\/[^\"]+\": \"\\^${current_version}\"/\"\\0\": \"^${new_version}\"/" \
|
||||
"$file" > "$tmp_file"
|
||||
fi
|
||||
|
||||
# Check if the temporary file exists and has content
|
||||
if [ -s "$tmp_file" ]; then
|
||||
mv "$tmp_file" "$file"
|
||||
echo " ${CHECK} Updated $file"
|
||||
else
|
||||
echo " ${WARNING} Failed to update $file"
|
||||
rm -f "$tmp_file"
|
||||
fi
|
||||
}
|
||||
|
||||
# Update version in files
|
||||
update_version() {
|
||||
local current_version=$1
|
||||
local new_version=$2
|
||||
|
||||
echo -e " ${UPDATE} Updating version numbers ($current_version → $new_version)\n"
|
||||
|
||||
# Update PHP class version
|
||||
echo -e " ${PACKAGE} Updating Flasher class version..."
|
||||
if [ -f "src/Prime/Flasher.php" ]; then
|
||||
sed -i '' "s/const VERSION = '$current_version'/const VERSION = '$new_version'/" src/Prime/Flasher.php
|
||||
echo -e " ${CHECK} Updated src/Prime/Flasher.php"
|
||||
fi
|
||||
|
||||
# Update composer.json files in src directory
|
||||
echo -e "\n ${PACKAGE} Updating composer.json files..."
|
||||
find src -name "composer.json" -type f | while read -r file; do
|
||||
update_composer_file "$file" "$current_version" "$new_version"
|
||||
done
|
||||
|
||||
# Update package.json files in src directory
|
||||
echo -e "\n ${PACKAGE} Updating package.json files..."
|
||||
find src -name "package.json" -type f | while read -r file; do
|
||||
update_package_file "$file" "$current_version" "$new_version"
|
||||
done
|
||||
|
||||
# Update root package.json
|
||||
if [ -f "package.json" ]; then
|
||||
update_package_file "package.json" "$current_version" "$new_version"
|
||||
fi
|
||||
|
||||
# Update docs package.json
|
||||
if [ -f "docs/package.json" ]; then
|
||||
update_package_file "docs/package.json" "$current_version" "$new_version"
|
||||
fi
|
||||
|
||||
echo -e "\n ${SUCCESS} Version bump complete!\n"
|
||||
}
|
||||
|
||||
# Main execution
|
||||
if [ -z "$1" ]; then
|
||||
echo -e "${RED}${ERROR} Version number is required${RESET}"
|
||||
echo -e "Usage: $0 <version>\n"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
print_header
|
||||
new_version=$1
|
||||
current_version=$(get_current_version)
|
||||
validate_version "$new_version"
|
||||
update_version "$current_version" "$new_version"
|
||||
@@ -1,70 +1,35 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
#!/bin/bash
|
||||
|
||||
declare(strict_types=1);
|
||||
# Default to the current directory if no directory is provided
|
||||
dir=${1:-.}
|
||||
|
||||
require __DIR__.'/../vendor/autoload.php';
|
||||
# Optional: A list of file extensions to filter by, e.g., "txt md". Leave empty to include all files.
|
||||
extensions=($2)
|
||||
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
# Temporary file to store results
|
||||
temp_file=$(mktemp)
|
||||
|
||||
$filesystem = new Filesystem();
|
||||
|
||||
// Define the shared resources
|
||||
$shared = realpath(__DIR__.'/../.shared');
|
||||
|
||||
$resources = [
|
||||
$shared,
|
||||
__DIR__.'/../.github/FUNDING.yml',
|
||||
__DIR__.'/../README.md',
|
||||
__DIR__.'/../LICENSE',
|
||||
];
|
||||
|
||||
// Directories to search for packages
|
||||
$dirs = [__DIR__.'/../src'];
|
||||
|
||||
// Find all composer.json files within the specified directories
|
||||
$finder = new Finder();
|
||||
$finder->files()
|
||||
->in($dirs)
|
||||
->name('composer.json')
|
||||
->depth('< 3'); // Adjust depth as needed
|
||||
|
||||
$packages = [];
|
||||
|
||||
// Collect package directories
|
||||
foreach ($finder as $file) {
|
||||
$packages[] = dirname($file->getRealPath());
|
||||
# Function to print file details (now inline within find command)
|
||||
print_file_details() {
|
||||
echo "File Path: $1"
|
||||
echo "Contents:"
|
||||
cat "$1"
|
||||
echo
|
||||
}
|
||||
|
||||
foreach ($packages as $packageDir) {
|
||||
foreach ($resources as $resource) {
|
||||
if (!is_string($resource)) {
|
||||
continue;
|
||||
}
|
||||
# Finding and processing files
|
||||
if [ ${#extensions[@]} -eq 0 ]; then
|
||||
# If no extensions are specified, process all files
|
||||
find "$dir" -type f -exec bash -c 'echo "File Path: $1"; echo "Contents:"; cat "$1"; echo' bash {} \; >> "$temp_file"
|
||||
else
|
||||
# Process only files with specified extensions
|
||||
for ext in "${extensions[@]}"; do
|
||||
find "$dir" -type f -name "*.$ext" -exec bash -c 'echo "File Path: $1"; echo "Contents:"; cat "$1"; echo' bash {} \; >> "$temp_file"
|
||||
done
|
||||
fi
|
||||
|
||||
$resourcePath = realpath($resource);
|
||||
# Copy results to clipboard and remove the temporary file
|
||||
cat "$temp_file" | pbcopy
|
||||
rm "$temp_file"
|
||||
|
||||
if (!$resourcePath) {
|
||||
continue; // Skip if the resource doesn't exist
|
||||
}
|
||||
|
||||
$relativePath = str_replace(realpath(__DIR__.'/../') ?: '', '', $resourcePath);
|
||||
$destination = $packageDir.$relativePath;
|
||||
|
||||
if (is_file($resourcePath)) {
|
||||
// Ensure the destination directory exists
|
||||
$filesystem->mkdir(dirname($destination));
|
||||
// Copy the file
|
||||
$filesystem->copy($resourcePath, $destination, true);
|
||||
} elseif (is_dir($resourcePath)) {
|
||||
if ($resourcePath === $shared) {
|
||||
// Copy contents of the shared directory into the package directory
|
||||
$filesystem->mirror($shared, $packageDir, null, ['override' => true]);
|
||||
} else {
|
||||
// Copy the entire directory to the destination
|
||||
$filesystem->mirror($resourcePath, $destination, null, ['override' => true]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
echo "Results copied to clipboard."
|
||||
|
||||
Executable
+129
@@ -0,0 +1,129 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -o pipefail
|
||||
|
||||
# PHP binary to use (defaults to PHP 8.2)
|
||||
PHP_BINARY="${PHP_BINARY:-/opt/homebrew/opt/php@8.2/bin/php}"
|
||||
|
||||
# Colors and styles
|
||||
readonly RESET='\033[0m'
|
||||
readonly BOLD='\033[1m'
|
||||
readonly DIM='\033[2m'
|
||||
readonly BLUE='\033[34m'
|
||||
readonly GREEN='\033[32m'
|
||||
readonly RED='\033[31m'
|
||||
readonly YELLOW='\033[33m'
|
||||
readonly CYAN='\033[36m'
|
||||
readonly MAGENTA='\033[35m'
|
||||
|
||||
# Essential emojis
|
||||
readonly ROCKET="🚀"
|
||||
readonly CHECK="✓"
|
||||
readonly ERROR="❌"
|
||||
readonly WARNING="⚠️"
|
||||
readonly CHART="📊"
|
||||
readonly TEST_TUBE="🧪"
|
||||
readonly SPARKLES="✨"
|
||||
readonly GLOBE="🌐"
|
||||
|
||||
print_header() {
|
||||
echo -e "\n${BOLD}${BLUE}${ROCKET} PHP-Flasher Test Coverage ${ROCKET}${RESET}\n"
|
||||
echo -e "${BOLD}Date : ${RESET}${CYAN}$(date -u '+%Y-%m-%d %H:%M:%S') UTC${RESET}"
|
||||
echo -e "${BOLD}Directory : ${RESET}${BLUE}$(pwd)${RESET}\n"
|
||||
}
|
||||
|
||||
cleanup_coverage() {
|
||||
echo -e "${BOLD}${DIM}Cleaning up old coverage reports...${RESET}"
|
||||
rm -rf coverage/phpunit coverage/vitest
|
||||
mkdir -p coverage/phpunit coverage/vitest
|
||||
echo -e "${CHECK} ${GREEN}Cleanup complete${RESET}\n"
|
||||
}
|
||||
|
||||
run_phpunit_coverage() {
|
||||
echo -e "${BOLD}${TEST_TUBE} Running PHPUnit with Coverage${RESET}"
|
||||
|
||||
if $PHP_BINARY vendor/bin/phpunit --coverage-html coverage/phpunit/html --coverage-text=coverage/phpunit/report.txt; then
|
||||
echo -e "${CHECK} ${GREEN}PHPUnit coverage generated${RESET}"
|
||||
echo -e " ${DIM}HTML Report: coverage/phpunit/html/index.html${RESET}\n"
|
||||
return 0
|
||||
else
|
||||
echo -e "${WARNING} ${YELLOW}PHPUnit coverage generation failed${RESET}\n"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
run_vitest_coverage() {
|
||||
echo -e "${BOLD}${TEST_TUBE} Running Vitest with Coverage${RESET}"
|
||||
|
||||
if npm run test:coverage; then
|
||||
echo -e "${CHECK} ${GREEN}Vitest coverage generated${RESET}"
|
||||
echo -e " ${DIM}HTML Report: coverage/vitest/index.html${RESET}\n"
|
||||
return 0
|
||||
else
|
||||
echo -e "${WARNING} ${YELLOW}Vitest coverage generation failed${RESET}\n"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
print_summary() {
|
||||
echo -e "${BOLD}${CYAN}${CHART} Coverage Reports Summary${RESET}\n"
|
||||
|
||||
echo -e "${BOLD}PHPUnit Coverage:${RESET}"
|
||||
if [ -f "coverage/phpunit/html/index.html" ]; then
|
||||
echo -e " ${GREEN}${CHECK} HTML: ${RESET}coverage/phpunit/html/index.html"
|
||||
if [ -f "coverage/phpunit/report.txt" ]; then
|
||||
echo -e " ${GREEN}${CHECK} Text: ${RESET}coverage/phpunit/report.txt"
|
||||
fi
|
||||
else
|
||||
echo -e " ${RED}${ERROR} No coverage report generated${RESET}"
|
||||
fi
|
||||
|
||||
echo -e "\n${BOLD}Vitest Coverage:${RESET}"
|
||||
if [ -f "coverage/vitest/index.html" ]; then
|
||||
echo -e " ${GREEN}${CHECK} HTML: ${RESET}coverage/vitest/index.html"
|
||||
if [ -f "coverage/vitest/coverage-final.json" ]; then
|
||||
echo -e " ${GREEN}${CHECK} JSON: ${RESET}coverage/vitest/coverage-final.json"
|
||||
fi
|
||||
else
|
||||
echo -e " ${RED}${ERROR} No coverage report generated${RESET}"
|
||||
fi
|
||||
|
||||
echo -e "\n${BOLD}${GLOBE} Open Reports:${RESET}"
|
||||
echo -e " ${CYAN}npm run coverage:open${RESET}"
|
||||
echo -e " ${DIM}Or manually open the HTML files in your browser${RESET}\n"
|
||||
}
|
||||
|
||||
open_reports() {
|
||||
if [ "$1" == "--open" ] || [ "$1" == "-o" ]; then
|
||||
echo -e "${BOLD}${GLOBE} Opening coverage reports...${RESET}\n"
|
||||
|
||||
if [ -f "coverage/phpunit/html/index.html" ]; then
|
||||
open coverage/phpunit/html/index.html 2>/dev/null || xdg-open coverage/phpunit/html/index.html 2>/dev/null
|
||||
fi
|
||||
|
||||
if [ -f "coverage/vitest/index.html" ]; then
|
||||
open coverage/vitest/index.html 2>/dev/null || xdg-open coverage/vitest/index.html 2>/dev/null
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
main() {
|
||||
local start_time=$(date +%s)
|
||||
|
||||
print_header
|
||||
cleanup_coverage
|
||||
run_phpunit_coverage
|
||||
run_vitest_coverage
|
||||
|
||||
local end_time=$(date +%s)
|
||||
local duration=$((end_time - start_time))
|
||||
|
||||
print_summary
|
||||
|
||||
echo -e "${SPARKLES} ${BOLD}Coverage Complete${RESET}"
|
||||
echo -e "Duration: ${YELLOW}${duration}s${RESET}\n"
|
||||
|
||||
open_reports "$1"
|
||||
}
|
||||
|
||||
main "$@"
|
||||
@@ -1,35 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Default to the current directory if no directory is provided
|
||||
dir=${1:-.}
|
||||
|
||||
# Optional: A list of file extensions to filter by, e.g., "txt md". Leave empty to include all files.
|
||||
extensions=($2)
|
||||
|
||||
# Temporary file to store results
|
||||
temp_file=$(mktemp)
|
||||
|
||||
# Function to print file details (now inline within find command)
|
||||
print_file_details() {
|
||||
echo "File Path: $1"
|
||||
echo "Contents:"
|
||||
cat "$1"
|
||||
echo
|
||||
}
|
||||
|
||||
# Finding and processing files
|
||||
if [ ${#extensions[@]} -eq 0 ]; then
|
||||
# If no extensions are specified, process all files
|
||||
find "$dir" -type f -exec bash -c 'echo "File Path: $1"; echo "Contents:"; cat "$1"; echo' bash {} \; >> "$temp_file"
|
||||
else
|
||||
# Process only files with specified extensions
|
||||
for ext in "${extensions[@]}"; do
|
||||
find "$dir" -type f -name "*.$ext" -exec bash -c 'echo "File Path: $1"; echo "Contents:"; cat "$1"; echo' bash {} \; >> "$temp_file"
|
||||
done
|
||||
fi
|
||||
|
||||
# Copy results to clipboard and remove the temporary file
|
||||
cat "$temp_file" | pbcopy
|
||||
rm "$temp_file"
|
||||
|
||||
echo "Results copied to clipboard."
|
||||
@@ -0,0 +1,101 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -o pipefail
|
||||
|
||||
# Colors and styles
|
||||
readonly RESET='\033[0m'
|
||||
readonly BOLD='\033[1m'
|
||||
readonly DIM='\033[2m'
|
||||
readonly UNDERLINE='\033[4m'
|
||||
readonly BLUE='\033[34m'
|
||||
readonly GREEN='\033[32m'
|
||||
readonly RED='\033[31m'
|
||||
readonly YELLOW='\033[33m'
|
||||
readonly CYAN='\033[36m'
|
||||
readonly MAGENTA='\033[35m'
|
||||
|
||||
# Essential emojis
|
||||
readonly ROCKET="🚀"
|
||||
readonly CHECK="✓"
|
||||
readonly ERROR="❌"
|
||||
readonly WARNING="⚠️"
|
||||
readonly BOOKS="📚"
|
||||
readonly HAMMER="🏗️"
|
||||
readonly SPARKLES="✨"
|
||||
|
||||
print_header() {
|
||||
echo -e "\n${BOLD}${BLUE}${ROCKET} PHP-Flasher Documentation Builder ${ROCKET}${RESET}\n"
|
||||
echo -e "${BOLD}Date : ${RESET}${CYAN}$(date -u '+%Y-%m-%d %H:%M:%S') UTC${RESET}"
|
||||
echo -e "${BOLD}User : ${RESET}${MAGENTA}yoeunes${RESET}"
|
||||
echo -e "${BOLD}Branch : ${RESET}${GREEN}$(git rev-parse --abbrev-ref HEAD)${RESET}"
|
||||
echo -e "${BOLD}Directory : ${RESET}${BLUE}$(pwd)${RESET}\n"
|
||||
}
|
||||
|
||||
install_dependencies() {
|
||||
echo -e "${BOLD}${BOOKS} Installing dependencies${RESET}"
|
||||
|
||||
if npm install --force; then
|
||||
echo -e "${CHECK} ${GREEN}Dependencies installed successfully${RESET}\n"
|
||||
return 0
|
||||
else
|
||||
echo -e "${WARNING} ${YELLOW}Dependency installation had issues${RESET}\n"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
build_documentation() {
|
||||
echo -e "${BOLD}${HAMMER} Building documentation${RESET}"
|
||||
|
||||
if npm run build; then
|
||||
echo -e "${CHECK} ${GREEN}Documentation built successfully${RESET}\n"
|
||||
return 0
|
||||
else
|
||||
echo -e "${ERROR} ${RED}Documentation build failed${RESET}\n"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
main() {
|
||||
local command=${1:-"build"}
|
||||
local start_time=$(date +%s)
|
||||
local success=true
|
||||
|
||||
# Change directory to docs/
|
||||
if [[ ! -d "docs/" ]]; then
|
||||
echo -e "${ERROR} ${RED}Documentation directory 'docs/' not found${RESET}\n"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd docs/
|
||||
|
||||
print_header
|
||||
echo -e "${BOLD}Command : ${RESET}${CYAN}${command}${RESET}\n"
|
||||
|
||||
case $command in
|
||||
"build")
|
||||
install_dependencies || success=false
|
||||
build_documentation || success=false
|
||||
;;
|
||||
*)
|
||||
echo -e "${ERROR} ${RED}Unknown command: ${command}${RESET}"
|
||||
echo -e "Available commands: build"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
local end_time=$(date +%s)
|
||||
local duration=$((end_time - start_time))
|
||||
|
||||
# Summary
|
||||
echo -e "${BOLD}${CYAN}Documentation ${command^} Summary${RESET}"
|
||||
if [ "$success" = true ]; then
|
||||
echo -e "${SPARKLES} ${GREEN}Documentation ${command} completed successfully${RESET}"
|
||||
else
|
||||
echo -e "${WARNING} ${YELLOW}Documentation ${command} completed with issues${RESET}"
|
||||
fi
|
||||
echo -e "Duration : ${YELLOW}${duration}s${RESET}\n"
|
||||
|
||||
[ "$success" = true ] && exit 0 || exit 1
|
||||
}
|
||||
|
||||
main "$@"
|
||||
@@ -0,0 +1,174 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -o pipefail
|
||||
|
||||
# PHP binary to use (defaults to PHP 8.2)
|
||||
PHP_BINARY="${PHP_BINARY:-/opt/homebrew/opt/php@8.2/bin/php}"
|
||||
|
||||
# Colors and styles
|
||||
readonly RESET='\033[0m'
|
||||
readonly BOLD='\033[1m'
|
||||
readonly DIM='\033[2m'
|
||||
readonly UNDERLINE='\033[4m'
|
||||
readonly BLUE='\033[34m'
|
||||
readonly GREEN='\033[32m'
|
||||
readonly RED='\033[31m'
|
||||
readonly YELLOW='\033[33m'
|
||||
readonly CYAN='\033[36m'
|
||||
readonly MAGENTA='\033[35m'
|
||||
|
||||
# Essential emojis
|
||||
readonly ROCKET="🚀"
|
||||
readonly CHECK="✓"
|
||||
readonly ERROR="❌"
|
||||
readonly WARNING="⚠️"
|
||||
readonly SEARCH="🔍"
|
||||
readonly PALETTE="🎨"
|
||||
readonly MICROSCOPE="🔬"
|
||||
readonly MEMO="📝"
|
||||
readonly MAGNIFIER="🔎"
|
||||
readonly TEST_TUBE="🧪"
|
||||
readonly SPARKLES="✨"
|
||||
|
||||
print_header() {
|
||||
echo -e "\n${BOLD}${BLUE}${ROCKET} PHP-Flasher Code Quality Check ${ROCKET}${RESET}\n"
|
||||
echo -e "${BOLD}Date : ${RESET}${CYAN}$(date -u '+%Y-%m-%d %H:%M:%S') UTC${RESET}"
|
||||
echo -e "${BOLD}User : ${RESET}${MAGENTA}yoeunes${RESET}"
|
||||
echo -e "${BOLD}Branch : ${RESET}${GREEN}$(git rev-parse --abbrev-ref HEAD)${RESET}"
|
||||
echo -e "${BOLD}Directory : ${RESET}${BLUE}$(pwd)${RESET}\n"
|
||||
}
|
||||
|
||||
run_rector() {
|
||||
echo -e "${BOLD}${SEARCH} Running Rector${RESET}"
|
||||
|
||||
if $PHP_BINARY vendor/bin/rector; then
|
||||
echo -e "${CHECK} ${GREEN}Rector completed successfully${RESET}\n"
|
||||
return 0
|
||||
else
|
||||
echo -e "${WARNING} ${YELLOW}Rector found issues${RESET}\n"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
run_php_cs_fixer() {
|
||||
echo -e "${BOLD}${PALETTE} Running PHP-CS-Fixer${RESET}"
|
||||
|
||||
if $PHP_BINARY vendor/bin/php-cs-fixer fix -v; then
|
||||
echo -e "${CHECK} ${GREEN}PHP-CS-Fixer completed successfully${RESET}\n"
|
||||
return 0
|
||||
else
|
||||
echo -e "${WARNING} ${YELLOW}CS-Fixer found issues${RESET}\n"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
run_phpstan() {
|
||||
echo -e "${BOLD}${MICROSCOPE} Running PHPStan${RESET}"
|
||||
|
||||
if $PHP_BINARY vendor/bin/phpstan analyse --memory-limit=-1; then
|
||||
echo -e "${CHECK} ${GREEN}PHPStan analysis completed successfully${RESET}\n"
|
||||
return 0
|
||||
else
|
||||
echo -e "${WARNING} ${YELLOW}PHPStan found issues${RESET}\n"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
validate_composer_files() {
|
||||
echo -e "${BOLD}${MEMO} Validating Composer Files${RESET}"
|
||||
local validation_success=true
|
||||
|
||||
if ! composer validate --strict; then
|
||||
echo -e "${WARNING} ${YELLOW}Main composer.json validation failed${RESET}"
|
||||
validation_success=false
|
||||
fi
|
||||
|
||||
# Find and validate all composer.json files in src/
|
||||
find src/ -name "composer.json" | while read file; do
|
||||
echo -e "${DIM}Validating ${file}${RESET}"
|
||||
if ! composer validate --strict "$file"; then
|
||||
echo -e "${WARNING} ${YELLOW}Package validation failed for ${file}${RESET}"
|
||||
validation_success=false
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$validation_success" = true ]; then
|
||||
echo -e "${CHECK} ${GREEN}All composer.json files are valid${RESET}\n"
|
||||
return 0
|
||||
else
|
||||
echo -e "${WARNING} ${YELLOW}Some composer.json files have issues${RESET}\n"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
run_phplint() {
|
||||
echo -e "${BOLD}${MAGNIFIER} Running PHPLint${RESET}"
|
||||
|
||||
if $PHP_BINARY vendor/bin/phplint; then
|
||||
echo -e "${CHECK} ${GREEN}PHPLint completed successfully${RESET}\n"
|
||||
return 0
|
||||
else
|
||||
echo -e "${WARNING} ${YELLOW}PHPLint found issues${RESET}\n"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
run_phpunit() {
|
||||
echo -e "${BOLD}${TEST_TUBE} Running PHPUnit Tests${RESET}"
|
||||
|
||||
if $PHP_BINARY vendor/bin/phpunit; then
|
||||
echo -e "${CHECK} ${GREEN}All tests passed successfully${RESET}\n"
|
||||
return 0
|
||||
else
|
||||
echo -e "${WARNING} ${YELLOW}Tests failed${RESET}\n"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
run_vitest() {
|
||||
echo -e "${BOLD}${TEST_TUBE} Running Vitest Tests${RESET}"
|
||||
|
||||
if npm run test -- --run; then
|
||||
echo -e "${CHECK} ${GREEN}Vitest tests passed successfully${RESET}\n"
|
||||
return 0
|
||||
else
|
||||
echo -e "${WARNING} ${YELLOW}Vitest tests failed${RESET}\n"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
main() {
|
||||
local start_time=$(date +%s)
|
||||
local issues_found=false
|
||||
|
||||
print_header
|
||||
|
||||
# Run all quality tools
|
||||
run_rector || issues_found=true
|
||||
run_php_cs_fixer || issues_found=true
|
||||
run_phpstan || issues_found=true
|
||||
validate_composer_files || issues_found=true
|
||||
run_phplint || issues_found=true
|
||||
run_phpunit || issues_found=true
|
||||
run_vitest || issues_found=true
|
||||
|
||||
local end_time=$(date +%s)
|
||||
local duration=$((end_time - start_time))
|
||||
|
||||
# Summary
|
||||
echo -e "${BOLD}${CYAN}Quality Check Summary${RESET}"
|
||||
if [ "$issues_found" = true ]; then
|
||||
echo -e "${WARNING} ${YELLOW}Quality check completed with issues${RESET}"
|
||||
else
|
||||
echo -e "${SPARKLES} ${GREEN}All quality checks passed successfully${RESET}"
|
||||
fi
|
||||
echo -e "Duration : ${YELLOW}${duration}s${RESET}\n"
|
||||
|
||||
echo -e "${SPARKLES} ${BOLD}Quality Check Complete${RESET}"
|
||||
echo -e "${CHECK} All checks finished\n"
|
||||
|
||||
# We don't exit with error code because the original task continues despite failures
|
||||
exit 0
|
||||
}
|
||||
|
||||
main
|
||||
@@ -1,26 +1,225 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
# Set options
|
||||
set -o pipefail
|
||||
|
||||
NPM_FOLDERS=(
|
||||
"src/Prime/Resources"
|
||||
"src/Noty/Prime/Resources"
|
||||
"src/Notyf/Prime/Resources"
|
||||
"src/SweetAlert/Prime/Resources"
|
||||
"src/Toastr/Prime/Resources"
|
||||
# Define colors and styles
|
||||
readonly RESET='\033[0m'
|
||||
readonly BOLD='\033[1m'
|
||||
readonly DIM='\033[2m'
|
||||
readonly GREEN='\033[32m'
|
||||
readonly BLUE='\033[34m'
|
||||
readonly CYAN='\033[36m'
|
||||
readonly YELLOW='\033[33m'
|
||||
readonly RED='\033[31m'
|
||||
|
||||
# Define emoji
|
||||
readonly ROCKET="🚀"
|
||||
readonly NPM="📦"
|
||||
readonly CHECK="✓"
|
||||
readonly WARN="⚠️"
|
||||
readonly ERROR="❌"
|
||||
readonly LOADING="⏳"
|
||||
readonly SKIP="⏭️"
|
||||
|
||||
# Configuration
|
||||
readonly NPM_PACKAGES=(
|
||||
"src/Prime/Resources:@flasher/flasher"
|
||||
"src/Noty/Prime/Resources:@flasher/flasher-noty"
|
||||
"src/Notyf/Prime/Resources:@flasher/flasher-notyf"
|
||||
"src/SweetAlert/Prime/Resources:@flasher/flasher-sweetalert"
|
||||
"src/Toastr/Prime/Resources:@flasher/flasher-toastr"
|
||||
)
|
||||
|
||||
for folder in "${NPM_FOLDERS[@]}"; do
|
||||
if [ -d "$folder" ]; then
|
||||
echo ""
|
||||
echo "Publishing $folder to npm..."
|
||||
(
|
||||
cd "$folder"
|
||||
npm install
|
||||
npm version "$VERSION" --no-git-tag-version || true
|
||||
npm publish --access public
|
||||
)
|
||||
fi
|
||||
done
|
||||
# Print functions
|
||||
print_header() {
|
||||
echo -e "\n${BOLD}${BLUE}╭──────────────────────────────────────────╮${RESET}"
|
||||
echo -e "${BOLD}${BLUE}│ ${ROCKET} PHP-Flasher NPM Release ${ROCKET} │${RESET}"
|
||||
echo -e "${BOLD}${BLUE}╰──────────────────────────────────────────╯${RESET}\n"
|
||||
echo -e " ${DIM}Date : $(date -u '+%Y-%m-%d %H:%M:%S') UTC${RESET}"
|
||||
echo -e " ${DIM}User : $(whoami)${RESET}"
|
||||
echo -e " ${DIM}Directory: $(pwd)${RESET}"
|
||||
}
|
||||
|
||||
echo "Release $VERSION complete – tagged repositories and published packages to npm."
|
||||
print_section() {
|
||||
echo -e "\n${BOLD}${CYAN}┌─ $1 ${2:-}${RESET}"
|
||||
}
|
||||
|
||||
success_msg() {
|
||||
echo -e " ${GREEN}${CHECK} $*${RESET}"
|
||||
}
|
||||
|
||||
info_msg() {
|
||||
echo -e " ${BLUE}${LOADING} $*${RESET}"
|
||||
}
|
||||
|
||||
warning_msg() {
|
||||
echo -e " ${YELLOW}${WARN} $*${RESET}"
|
||||
}
|
||||
|
||||
error_msg() {
|
||||
echo -e " ${RED}${ERROR} $*${RESET}"
|
||||
}
|
||||
|
||||
skip_msg() {
|
||||
echo -e " ${YELLOW}${SKIP} $*${RESET}"
|
||||
}
|
||||
|
||||
print_summary() {
|
||||
local version=$1
|
||||
local duration=$2
|
||||
local success_count=$3
|
||||
local skipped_count=$4
|
||||
local failed_count=$5
|
||||
local failed_packages=("${@:6}")
|
||||
|
||||
print_section "Release Summary"
|
||||
echo -e "\n ${DIM}Version : ${BOLD}v${version}${RESET}"
|
||||
echo -e " ${DIM}Duration : ${BOLD}${duration}s${RESET}"
|
||||
|
||||
if [ "$success_count" -gt 0 ]; then
|
||||
echo -e "\n ${DIM}Published : ${GREEN}${success_count}${RESET} packages"
|
||||
fi
|
||||
|
||||
if [ "$skipped_count" -gt 0 ]; then
|
||||
echo -e "\n ${DIM}Skipped : ${YELLOW}${skipped_count}${RESET} packages"
|
||||
fi
|
||||
|
||||
if [ "$failed_count" -gt 0 ]; then
|
||||
echo -e "\n ${DIM}Failed : ${RED}${failed_count}${RESET} packages"
|
||||
echo -e "\n ${DIM}Failed packages:${RESET}"
|
||||
for package in "${failed_packages[@]}"; do
|
||||
echo -e " ${RED}• ${package}${RESET}"
|
||||
done
|
||||
fi
|
||||
|
||||
echo -e ""
|
||||
if [ "$success_count" -eq 0 ] && [ "$skipped_count" -gt 0 ]; then
|
||||
success_msg "All packages were already up to date! ${ROCKET}"
|
||||
elif [ "$success_count" -gt 0 ]; then
|
||||
success_msg "NPM release completed successfully! ${ROCKET}"
|
||||
elif [ "$failed_count" -gt 0 ]; then
|
||||
error_msg "NPM release completed with failures! ${ERROR}"
|
||||
fi
|
||||
}
|
||||
|
||||
# Check if version exists
|
||||
check_version_exists() {
|
||||
local package=$1
|
||||
local version=$2
|
||||
npm view "${package}@${version}" version >/dev/null 2>&1
|
||||
}
|
||||
|
||||
# Validate NPM is installed and logged in
|
||||
validate_npm() {
|
||||
print_section "NPM Authentication Check"
|
||||
|
||||
if ! command -v npm >/dev/null 2>&1; then
|
||||
error_msg "npm is not installed"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! npm whoami >/dev/null 2>&1; then
|
||||
error_msg "You are not logged in to npm. Please run 'npm login' first."
|
||||
return 1
|
||||
fi
|
||||
|
||||
success_msg "Authenticated as $(npm whoami)"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Process a single package
|
||||
process_package() {
|
||||
local path_and_name=$1
|
||||
local version=$2
|
||||
local path="${path_and_name%:*}"
|
||||
local package="${path_and_name#*:}"
|
||||
|
||||
print_section "Processing ${package}"
|
||||
|
||||
if [ ! -d "$path" ]; then
|
||||
warning_msg "Directory $path does not exist, skipping..."
|
||||
return 2
|
||||
fi
|
||||
|
||||
info_msg "Checking version ${version}..."
|
||||
if check_version_exists "$package" "$version"; then
|
||||
skip_msg "Version ${version} already exists for ${package}, skipping..."
|
||||
return 2
|
||||
fi
|
||||
|
||||
info_msg "Installing dependencies..."
|
||||
(cd "$path" && npm install --silent) || {
|
||||
error_msg "Failed to install dependencies"
|
||||
return 1
|
||||
}
|
||||
|
||||
info_msg "Updating package version..."
|
||||
(cd "$path" && npm version "$version" --no-git-tag-version --allow-same-version >/dev/null 2>&1) || true
|
||||
|
||||
info_msg "Publishing ${package}@${version}..."
|
||||
if (cd "$path" && npm publish --access public); then
|
||||
success_msg "Successfully published ${package}@${version}"
|
||||
return 0
|
||||
else
|
||||
error_msg "Failed to publish ${package}"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Main execution
|
||||
main() {
|
||||
if [ "$#" -ne 1 ]; then
|
||||
echo -e "\n${YELLOW}Usage: $0 <version>${RESET}"
|
||||
echo -e "Example: $0 2.1.5\n"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local VERSION=$1
|
||||
VERSION="${VERSION#v}"
|
||||
|
||||
print_header
|
||||
|
||||
# Validate npm authentication
|
||||
validate_npm || exit 1
|
||||
|
||||
# Track statistics
|
||||
local start_time=$(date +%s)
|
||||
local success_count=0
|
||||
local failed_count=0
|
||||
local skipped_count=0
|
||||
local failed_packages=()
|
||||
|
||||
# Process each package
|
||||
for package_info in "${NPM_PACKAGES[@]}"; do
|
||||
local package_name="${package_info#*:}"
|
||||
|
||||
process_package "$package_info" "$VERSION"
|
||||
local status=$?
|
||||
|
||||
case $status in
|
||||
0)
|
||||
((success_count++))
|
||||
;;
|
||||
1)
|
||||
((failed_count++))
|
||||
failed_packages+=("$package_name")
|
||||
;;
|
||||
2)
|
||||
((skipped_count++))
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Print summary
|
||||
local end_time=$(date +%s)
|
||||
local duration=$((end_time - start_time))
|
||||
|
||||
print_summary "$VERSION" "$duration" "$success_count" "$skipped_count" "$failed_count" "${failed_packages[@]}"
|
||||
|
||||
# Exit with failure if any package failed
|
||||
[ "$failed_count" -gt 0 ] && exit 1 || exit 0
|
||||
}
|
||||
|
||||
# Execute main function
|
||||
main "$@"
|
||||
|
||||
+224
-61
@@ -1,80 +1,243 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
set -o pipefail
|
||||
|
||||
# Make sure the release tag is provided.
|
||||
if (( "$#" != 1 ))
|
||||
then
|
||||
echo "Tag has to be provided."
|
||||
# Colors and styles
|
||||
readonly RESET='\033[0m'
|
||||
readonly BOLD='\033[1m'
|
||||
readonly DIM='\033[2m'
|
||||
readonly UNDERLINE='\033[4m'
|
||||
readonly BLUE='\033[34m'
|
||||
readonly GREEN='\033[32m'
|
||||
readonly RED='\033[31m'
|
||||
readonly YELLOW='\033[33m'
|
||||
readonly CYAN='\033[36m'
|
||||
readonly MAGENTA='\033[35m'
|
||||
|
||||
exit 1
|
||||
fi
|
||||
# Essential emojis
|
||||
readonly ROCKET="🚀"
|
||||
readonly CHECK="✓"
|
||||
readonly ERROR="❌"
|
||||
readonly SKIP="⏭️"
|
||||
|
||||
RELEASE_BRANCH="2.x"
|
||||
CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
|
||||
VERSION=$1
|
||||
# Configuration
|
||||
readonly RELEASE_BRANCH="2.x"
|
||||
readonly REPOSITORIES=(
|
||||
"flasher"
|
||||
"flasher-laravel"
|
||||
"flasher-symfony"
|
||||
"flasher-noty"
|
||||
"flasher-noty-laravel"
|
||||
"flasher-noty-symfony"
|
||||
"flasher-notyf"
|
||||
"flasher-notyf-laravel"
|
||||
"flasher-notyf-symfony"
|
||||
"flasher-sweetalert"
|
||||
"flasher-sweetalert-laravel"
|
||||
"flasher-sweetalert-symfony"
|
||||
"flasher-toastr"
|
||||
"flasher-toastr-laravel"
|
||||
"flasher-toastr-symfony"
|
||||
)
|
||||
|
||||
# Make sure current branch and release branch match.
|
||||
if [[ "$RELEASE_BRANCH" != "$CURRENT_BRANCH" ]]
|
||||
then
|
||||
echo "Release branch ($RELEASE_BRANCH) does not match the current active branch ($CURRENT_BRANCH)."
|
||||
print_header() {
|
||||
echo -e "\n${BOLD}${BLUE}${ROCKET} PHP-Flasher Release ${ROCKET}${RESET}\n"
|
||||
echo -e "${BOLD}Date : ${RESET}${CYAN}$(date -u '+%Y-%m-%d %H:%M:%S') UTC${RESET}"
|
||||
echo -e "${BOLD}User : ${RESET}${MAGENTA}$(whoami)${RESET}"
|
||||
echo -e "${BOLD}Branch : ${RESET}${GREEN}$RELEASE_BRANCH${RESET}"
|
||||
echo -e "${BOLD}Directory : ${RESET}${BLUE}$(pwd)${RESET}\n"
|
||||
}
|
||||
|
||||
exit 1
|
||||
fi
|
||||
draw_progress_bar() {
|
||||
local percent=$1
|
||||
local width=50
|
||||
local filled=$(((width * percent + 99) / 100)) # Rounded up division
|
||||
local empty=$((width - filled))
|
||||
|
||||
# Make sure the working directory is clear.
|
||||
if [[ ! -z "$(git status --porcelain)" ]]
|
||||
then
|
||||
echo "Your working directory is dirty. Did you forget to commit your changes?"
|
||||
echo -n "["
|
||||
printf "${GREEN}█%.0s${RESET}" $(seq 1 $filled)
|
||||
printf "${DIM}─%.0s${RESET}" $(seq 1 $empty)
|
||||
echo -n "] ${percent}%"
|
||||
}
|
||||
|
||||
exit 1
|
||||
fi
|
||||
check_tag_exists() {
|
||||
local repo=$1
|
||||
local tag=$2
|
||||
local remote_url="git@github.com:php-flasher/$repo.git"
|
||||
|
||||
# Make sure latest changes are fetched first.
|
||||
git fetch origin
|
||||
if git ls-remote --tags "$remote_url" | grep -q "refs/tags/$tag$"; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Make sure that release branch is in sync with origin.
|
||||
if [[ $(git rev-parse HEAD) != $(git rev-parse origin/$RELEASE_BRANCH) ]]
|
||||
then
|
||||
echo "Your branch is out of date with its upstream. Did you forget to pull or push any changes before releasing?"
|
||||
release_repository() {
|
||||
local repo=$1
|
||||
local version=$2
|
||||
local tmp_dir="/tmp/php-flasher"
|
||||
local remote_url="git@github.com:php-flasher/$repo.git"
|
||||
|
||||
exit 1
|
||||
fi
|
||||
echo -e "\nGitHub : ${UNDERLINE}${BLUE}https://github.com/php-flasher/${repo}${RESET}"
|
||||
echo -e "Tag : ${YELLOW}$version${RESET}"
|
||||
|
||||
# Always prepend with "v"
|
||||
if [[ $VERSION != v* ]]
|
||||
then
|
||||
VERSION="v$VERSION"
|
||||
fi
|
||||
if check_tag_exists "$repo" "$version"; then
|
||||
echo -e "${SKIP} ${YELLOW}Tag $version already exists, skipping...${RESET}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Tag PHPFlasher
|
||||
git tag "$VERSION"
|
||||
git push origin --tags --force
|
||||
# Clean and create temporary directory
|
||||
rm -rf "$tmp_dir"
|
||||
mkdir -p "$tmp_dir"
|
||||
|
||||
# Tag Repositories
|
||||
for REMOTE in flasher flasher-laravel flasher-symfony \
|
||||
flasher-noty flasher-noty-laravel flasher-noty-symfony \
|
||||
flasher-notyf flasher-notyf-laravel flasher-notyf-symfony \
|
||||
flasher-sweetalert flasher-sweetalert-laravel flasher-sweetalert-symfony \
|
||||
flasher-toastr flasher-toastr-laravel flasher-toastr-symfony
|
||||
do
|
||||
echo ""
|
||||
echo ""
|
||||
echo "Releasing $REMOTE";
|
||||
|
||||
TMP_DIR="/tmp/php-flasher"
|
||||
REMOTE_URL="git@github.com:php-flasher/$REMOTE.git"
|
||||
|
||||
rm -rf $TMP_DIR;
|
||||
mkdir $TMP_DIR;
|
||||
echo -e "${CYAN}Cloning repository...${RESET}"
|
||||
if ! git clone "$remote_url" "$tmp_dir" >/dev/null 2>&1; then
|
||||
echo -e "${ERROR} ${RED}Failed to clone repository${RESET}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
(
|
||||
cd $TMP_DIR;
|
||||
cd "$tmp_dir"
|
||||
echo -e "${CYAN}Creating tag $version...${RESET}"
|
||||
git checkout "$RELEASE_BRANCH" >/dev/null 2>&1
|
||||
git tag "$version"
|
||||
|
||||
git clone $REMOTE_URL .
|
||||
git checkout "$RELEASE_BRANCH";
|
||||
|
||||
git tag "$VERSION"
|
||||
git push origin --tags --force
|
||||
if ! git push origin --tags --force >/dev/null 2>&1; then
|
||||
echo -e "${ERROR} ${RED}Failed to push tag${RESET}"
|
||||
return 1
|
||||
fi
|
||||
)
|
||||
done
|
||||
|
||||
echo -e "${CHECK} ${GREEN}Successfully tagged${RESET}"
|
||||
return 0
|
||||
}
|
||||
|
||||
validate_version() {
|
||||
local version=$1
|
||||
if [[ ! $version =~ ^v?[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||||
echo -e "\n${ERROR} ${RED}Invalid version format: $version${RESET}"
|
||||
echo -e "Version must be in format X.Y.Z or vX.Y.Z (e.g., 2.1.6 or v2.1.6)\n"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
validate_environment() {
|
||||
echo -e "${CYAN}Validating environment...${RESET}"
|
||||
local has_error=0
|
||||
|
||||
# Check branch
|
||||
local current_branch=$(git rev-parse --abbrev-ref HEAD)
|
||||
echo -ne "${CYAN}Checking branch...${RESET} "
|
||||
if [[ "$RELEASE_BRANCH" != "$current_branch" ]]; then
|
||||
echo -e "${ERROR} ${RED}Wrong branch: $current_branch (expected: $RELEASE_BRANCH)${RESET}"
|
||||
has_error=1
|
||||
else
|
||||
echo -e "${CHECK} ${GREEN}On correct branch: $current_branch${RESET}"
|
||||
fi
|
||||
|
||||
# Check working directory
|
||||
echo -ne "${CYAN}Checking working directory...${RESET} "
|
||||
if [[ ! -z "$(git status --porcelain)" ]]; then
|
||||
echo -e "${ERROR} ${RED}Working directory is not clean${RESET}"
|
||||
echo -e "${DIM}Hint: Commit or stash your changes first${RESET}"
|
||||
has_error=1
|
||||
else
|
||||
echo -e "${CHECK} ${GREEN}Working directory is clean${RESET}"
|
||||
fi
|
||||
|
||||
# Check sync with remote
|
||||
echo -ne "${CYAN}Checking remote synchronization...${RESET} "
|
||||
git fetch origin > /dev/null 2>&1
|
||||
local local_sha=$(git rev-parse HEAD)
|
||||
local remote_sha=$(git rev-parse origin/$RELEASE_BRANCH)
|
||||
|
||||
if [[ $local_sha != $remote_sha ]]; then
|
||||
echo -e "${ERROR} ${RED}Branch is not in sync with origin/$RELEASE_BRANCH${RESET}"
|
||||
echo -e "\n${YELLOW}Local SHA: ${local_sha}${RESET}"
|
||||
echo -e "${YELLOW}Remote SHA: ${remote_sha}${RESET}"
|
||||
echo -e "\n${DIM}To fix this, try:${RESET}"
|
||||
|
||||
# Check if we have unpushed commits
|
||||
if git rev-list origin/$RELEASE_BRANCH..$RELEASE_BRANCH --count > /dev/null 2>&1; then
|
||||
local ahead=$(git rev-list origin/$RELEASE_BRANCH..$RELEASE_BRANCH --count)
|
||||
local behind=$(git rev-list $RELEASE_BRANCH..origin/$RELEASE_BRANCH --count)
|
||||
|
||||
if [[ $ahead -gt 0 && $behind -gt 0 ]]; then
|
||||
echo -e "${YELLOW}Your branch is $ahead commits ahead and $behind commits behind origin/$RELEASE_BRANCH${RESET}"
|
||||
echo -e "1. ${CYAN}git pull origin $RELEASE_BRANCH${RESET} (to get remote changes)"
|
||||
echo -e "2. ${CYAN}git push origin $RELEASE_BRANCH${RESET} (to push your changes)"
|
||||
elif [[ $ahead -gt 0 ]]; then
|
||||
echo -e "${YELLOW}Your branch is $ahead commits ahead of origin/$RELEASE_BRANCH${RESET}"
|
||||
echo -e "Run: ${CYAN}git push origin $RELEASE_BRANCH${RESET}"
|
||||
elif [[ $behind -gt 0 ]]; then
|
||||
echo -e "${YELLOW}Your branch is $behind commits behind origin/$RELEASE_BRANCH${RESET}"
|
||||
echo -e "Run: ${CYAN}git pull origin $RELEASE_BRANCH${RESET}"
|
||||
fi
|
||||
fi
|
||||
has_error=1
|
||||
else
|
||||
echo -e "${CHECK} ${GREEN}Branch is in sync with remote${RESET}"
|
||||
fi
|
||||
|
||||
if [[ $has_error -eq 1 ]]; then
|
||||
echo -e "\n${ERROR} ${RED}Environment validation failed${RESET}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "\n${CHECK} ${GREEN}Environment validated successfully${RESET}\n"
|
||||
}
|
||||
|
||||
main() {
|
||||
if [ "$#" -ne 1 ]; then
|
||||
echo -e "${ERROR} ${RED}Version tag required${RESET}"
|
||||
echo -e "Usage: $0 <version>"
|
||||
echo -e "Example: $0 2.1.6\n"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local version=$1
|
||||
[[ $version != v* ]] && version="v$version"
|
||||
|
||||
print_header
|
||||
validate_version "$version"
|
||||
validate_environment
|
||||
|
||||
local success_count=0
|
||||
local skipped_count=0
|
||||
local failed_count=0
|
||||
local total_count=${#REPOSITORIES[@]}
|
||||
local start_time=$(date +%s)
|
||||
|
||||
for repo in "${REPOSITORIES[@]}"; do
|
||||
local current_count=$((success_count + skipped_count + failed_count + 1))
|
||||
local percent=$((current_count * 100 / total_count))
|
||||
|
||||
echo -e "\nProgress: ${BOLD}$current_count/$total_count${RESET}"
|
||||
# draw_progress_bar $percent
|
||||
|
||||
if release_repository "$repo" "$version"; then
|
||||
if check_tag_exists "$repo" "$version"; then
|
||||
((skipped_count++))
|
||||
else
|
||||
((success_count++))
|
||||
fi
|
||||
else
|
||||
((failed_count++))
|
||||
fi
|
||||
done
|
||||
|
||||
local end_time=$(date +%s)
|
||||
local duration=$((end_time - start_time))
|
||||
|
||||
# Summary
|
||||
echo -e "\n${BOLD}${CYAN}Release Summary${RESET}"
|
||||
echo -e "Successful : ${GREEN}$success_count${RESET}"
|
||||
echo -e "Skipped : ${YELLOW}$skipped_count${RESET}"
|
||||
[ $failed_count -gt 0 ] && echo -e "Failed : ${RED}$failed_count${RESET}"
|
||||
echo -e "Duration : ${YELLOW}${duration}s${RESET}"
|
||||
echo -e "Total repos: ${CYAN}$total_count${RESET}\n"
|
||||
|
||||
[ $failed_count -gt 0 ] && exit 1 || exit 0
|
||||
}
|
||||
|
||||
main "$@"
|
||||
|
||||
@@ -1,108 +1,154 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Set the "errexit" options
|
||||
set -o errexit
|
||||
set -o pipefail
|
||||
|
||||
# Define colors and emoji for better visual feedback
|
||||
INDIGO='\033[0;94m'
|
||||
GREEN='\033[0;32m'
|
||||
NC='\033[0m' # No Color
|
||||
CHECK_MARK="✅"
|
||||
CROSS_MARK="❌"
|
||||
# Colors and styles
|
||||
readonly RESET='\033[0m'
|
||||
readonly BOLD='\033[1m'
|
||||
readonly DIM='\033[2m'
|
||||
readonly UNDERLINE='\033[4m'
|
||||
readonly BLUE='\033[34m'
|
||||
readonly GREEN='\033[32m'
|
||||
readonly RED='\033[31m'
|
||||
readonly YELLOW='\033[33m'
|
||||
readonly CYAN='\033[36m'
|
||||
readonly MAGENTA='\033[35m'
|
||||
|
||||
# Initialize global flags
|
||||
DEBUG=0
|
||||
DRY_RUN=0
|
||||
# Essential emojis
|
||||
readonly ROCKET="🚀"
|
||||
readonly CHECK="✓"
|
||||
readonly ERROR="❌"
|
||||
|
||||
# Process command-line arguments
|
||||
for arg in "$@"; do
|
||||
case $arg in
|
||||
--debug)
|
||||
DEBUG=1
|
||||
shift
|
||||
;;
|
||||
--dry-run)
|
||||
DRY_RUN=1
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
# Unknown option
|
||||
;;
|
||||
esac
|
||||
done
|
||||
# Repository mappings
|
||||
declare -A REPOSITORIES=(
|
||||
# Core packages
|
||||
["src/Prime"]="flasher"
|
||||
["src/Laravel"]="flasher-laravel"
|
||||
["src/Symfony"]="flasher-symfony"
|
||||
|
||||
# Debug message function
|
||||
debug_msg() {
|
||||
if [ "$DEBUG" -eq 1 ]; then
|
||||
echo -e "${INDIGO}Debug: $*${NC}"
|
||||
fi
|
||||
}
|
||||
# Toastr packages
|
||||
["src/Toastr/Prime"]="flasher-toastr"
|
||||
["src/Toastr/Laravel"]="flasher-toastr-laravel"
|
||||
["src/Toastr/Symfony"]="flasher-toastr-symfony"
|
||||
|
||||
# Define remotes
|
||||
REMOTES=(
|
||||
'src/Prime:flasher'
|
||||
'src/Laravel:flasher-laravel'
|
||||
'src/Symfony:flasher-symfony'
|
||||
# Notyf packages
|
||||
["src/Notyf/Prime"]="flasher-notyf"
|
||||
["src/Notyf/Laravel"]="flasher-notyf-laravel"
|
||||
["src/Notyf/Symfony"]="flasher-notyf-symfony"
|
||||
|
||||
'src/Toastr/Prime:flasher-toastr'
|
||||
'src/Toastr/Laravel:flasher-toastr-laravel'
|
||||
'src/Toastr/Symfony:flasher-toastr-symfony'
|
||||
# SweetAlert packages
|
||||
["src/SweetAlert/Prime"]="flasher-sweetalert"
|
||||
["src/SweetAlert/Laravel"]="flasher-sweetalert-laravel"
|
||||
["src/SweetAlert/Symfony"]="flasher-sweetalert-symfony"
|
||||
|
||||
'src/Notyf/Prime:flasher-notyf'
|
||||
'src/Notyf/Laravel:flasher-notyf-laravel'
|
||||
'src/Notyf/Symfony:flasher-notyf-symfony'
|
||||
|
||||
'src/SweetAlert/Prime:flasher-sweetalert'
|
||||
'src/SweetAlert/Laravel:flasher-sweetalert-laravel'
|
||||
'src/SweetAlert/Symfony:flasher-sweetalert-symfony'
|
||||
|
||||
'src/Noty/Prime:flasher-noty'
|
||||
'src/Noty/Laravel:flasher-noty-laravel'
|
||||
'src/Noty/Symfony:flasher-noty-symfony'
|
||||
# Noty packages
|
||||
["src/Noty/Prime"]="flasher-noty"
|
||||
["src/Noty/Laravel"]="flasher-noty-laravel"
|
||||
["src/Noty/Symfony"]="flasher-noty-symfony"
|
||||
)
|
||||
|
||||
# Function to get the current git branch name
|
||||
function current_branch() {
|
||||
git rev-parse --abbrev-ref HEAD
|
||||
print_header() {
|
||||
echo -e "\n${BOLD}${BLUE}${ROCKET} PHP-Flasher Split ${ROCKET}${RESET}\n"
|
||||
echo -e "${BOLD}Date : ${RESET}${CYAN}$(date -u '+%Y-%m-%d %H:%M:%S') UTC${RESET}"
|
||||
echo -e "${BOLD}User : ${RESET}${MAGENTA}$(whoami)${RESET}"
|
||||
echo -e "${BOLD}Branch : ${RESET}${GREEN}$(git rev-parse --abbrev-ref HEAD)${RESET}"
|
||||
echo -e "${BOLD}Directory : ${RESET}${BLUE}$(pwd)${RESET}\n"
|
||||
}
|
||||
|
||||
# Define a function to split and push code to a remote repository
|
||||
function split() {
|
||||
local prefix_and_remote="$1"
|
||||
local prefix="${prefix_and_remote%:*}"
|
||||
local remote="${prefix_and_remote#*:}"
|
||||
local current_branch=$(current_branch)
|
||||
process_split() {
|
||||
local prefix=$1
|
||||
local remote=${REPOSITORIES[$prefix]}
|
||||
local branch=$(git rev-parse --abbrev-ref HEAD)
|
||||
local repo_url="https://github.com/php-flasher/${remote}"
|
||||
local packagist_url="https://packagist.org/packages/php-flasher/${remote}"
|
||||
|
||||
# Add remote if it does not exist (ignoring errors silently)
|
||||
if git remote add "$remote" "git@github.com:php-flasher/$remote.git" 2>/dev/null; then
|
||||
echo -e "${GREEN}Added remote ${INDIGO}$remote${NC} ${CHECK_MARK}"
|
||||
else
|
||||
debug_msg "Remote $remote already exists or could not be added."
|
||||
echo -e "\nGitHub : ${UNDERLINE}${BLUE}${repo_url}${RESET}"
|
||||
echo -e "Package : ${UNDERLINE}${BLUE}${packagist_url}${RESET}"
|
||||
echo -e "Prefix : ${YELLOW}$prefix${RESET}"
|
||||
echo -e "Branch : ${GREEN}$branch${RESET}\n"
|
||||
|
||||
# Split the repository
|
||||
echo -e "${CYAN}Splitting code...${RESET}"
|
||||
local sha1
|
||||
if ! sha1=$(./bin/splitsh-lite --prefix="$prefix" 2>/dev/null); then
|
||||
echo -e "${ERROR} ${RED}Split failed${RESET}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Split the code using the splitsh-lite utility
|
||||
SHA1=$(./bin/splitsh-lite --prefix="$prefix")
|
||||
debug_msg "SHA1 for $prefix is $SHA1."
|
||||
echo -e "${CHECK} Split complete (SHA: ${YELLOW}${sha1:0:8}${RESET})"
|
||||
echo -e "${CYAN}Pushing to remote...${RESET}"
|
||||
|
||||
# Push the code to the remote repository on the same branch as the current branch
|
||||
if [ "$DRY_RUN" -eq 0 ]; then
|
||||
git push "$remote" "$SHA1:refs/heads/$current_branch" -f
|
||||
else
|
||||
echo -e "${INDIGO}Dry run: Would push $SHA1 to $remote on branch $current_branch${NC}"
|
||||
if ! git push "$remote" "$sha1:refs/heads/$branch" -f > /dev/null 2>&1; then
|
||||
echo -e "${ERROR} ${RED}Failed to push to $remote${RESET}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo -e "${CHECK} ${GREEN}Pushed to $remote (branch: $branch)${RESET}"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Pull the latest code from the origin repository
|
||||
if [ "$DRY_RUN" -eq 0 ]; then
|
||||
echo -e "${INDIGO}Pulling the latest code from the origin repository on branch ${current_branch}...${NC}"
|
||||
git fetch origin "$current_branch"
|
||||
else
|
||||
echo -e "${INDIGO}Dry run: Would fetch latest code for branch $current_branch from the origin repository.${NC}"
|
||||
fi
|
||||
update_repository() {
|
||||
echo -e "\n${CYAN}Fetching latest changes...${RESET}"
|
||||
if ! git fetch origin "$(git rev-parse --abbrev-ref HEAD)" > /dev/null 2>&1; then
|
||||
echo -e "${ERROR} ${RED}Failed to fetch latest changes, continuing...${RESET}"
|
||||
else
|
||||
echo -e "${CHECK} ${GREEN}Repository updated successfully${RESET}"
|
||||
fi
|
||||
echo
|
||||
}
|
||||
|
||||
# Iterate over the remotes and split and push the code
|
||||
for remote in "${REMOTES[@]}"; do
|
||||
split "$remote"
|
||||
done
|
||||
draw_progress_bar() {
|
||||
local percent=$1
|
||||
local width=50
|
||||
local filled=$(( (width * percent + 99) / 100 )) # Rounded up division
|
||||
local empty=$(( width - filled ))
|
||||
|
||||
echo -e "${GREEN}All done!${NC} ${CHECK_MARK}"
|
||||
echo -n "["
|
||||
printf "${GREEN}█%.0s${RESET}" $(seq 1 $filled)
|
||||
printf "${DIM}─%.0s${RESET}" $(seq 1 $empty)
|
||||
echo -n "] ${percent}%"
|
||||
}
|
||||
|
||||
main() {
|
||||
print_header
|
||||
update_repository
|
||||
|
||||
local success_count=0
|
||||
local failed_count=0
|
||||
local total_count=${#REPOSITORIES[@]}
|
||||
local start_time=$(date +%s)
|
||||
|
||||
for prefix in "${!REPOSITORIES[@]}"; do
|
||||
local current_count=$((success_count + failed_count + 1))
|
||||
local percent=$((current_count * 100 / total_count))
|
||||
|
||||
echo -e "\nProgress: ${BOLD}$current_count/$total_count${RESET}"
|
||||
# draw_progress_bar $percent
|
||||
|
||||
if process_split "$prefix"; then
|
||||
((success_count++))
|
||||
else
|
||||
((failed_count++))
|
||||
fi
|
||||
done
|
||||
|
||||
local end_time=$(date +%s)
|
||||
local duration=$((end_time - start_time))
|
||||
|
||||
# Summary
|
||||
echo -e "\n${BOLD}${CYAN}Split Summary${RESET}"
|
||||
echo -e "Successful : ${GREEN}$success_count${RESET}"
|
||||
[ $failed_count -gt 0 ] && echo -e "Failed : ${RED}$failed_count${RESET}"
|
||||
echo -e "Duration : ${YELLOW}${duration}s${RESET}"
|
||||
echo -e "Total repos : ${CYAN}$total_count${RESET}"
|
||||
|
||||
# Links
|
||||
echo -e "\n${BOLD}${CYAN}Quick Links${RESET}"
|
||||
echo -e "Packagist : ${UNDERLINE}${BLUE}https://packagist.org/packages/php-flasher/${RESET}"
|
||||
echo -e "NPM : ${UNDERLINE}${BLUE}https://www.npmjs.com/org/flasher${RESET}"
|
||||
echo -e "GitHub : ${UNDERLINE}${BLUE}https://github.com/php-flasher${RESET}\n"
|
||||
|
||||
[ $failed_count -gt 0 ] && exit 1 || exit 0
|
||||
}
|
||||
|
||||
main
|
||||
|
||||
Executable
+331
@@ -0,0 +1,331 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Set options
|
||||
set -e
|
||||
set -o pipefail
|
||||
|
||||
# Define colors and styles
|
||||
readonly RESET='\033[0m'
|
||||
readonly BOLD='\033[1m'
|
||||
readonly DIM='\033[2m'
|
||||
readonly ITALIC='\033[3m'
|
||||
readonly UNDERLINE='\033[4m'
|
||||
readonly RED='\033[31m'
|
||||
readonly GREEN='\033[32m'
|
||||
readonly YELLOW='\033[33m'
|
||||
readonly BLUE='\033[34m'
|
||||
readonly MAGENTA='\033[35m'
|
||||
readonly CYAN='\033[36m'
|
||||
readonly WHITE='\033[37m'
|
||||
|
||||
# Define emoji
|
||||
readonly ROCKET="🚀"
|
||||
readonly PACKAGE="📦"
|
||||
readonly CALENDAR="📅"
|
||||
readonly CLOCK="🕒"
|
||||
readonly INFO="ℹ️"
|
||||
readonly WARNING="⚠️"
|
||||
readonly CHECK="✓"
|
||||
readonly BRANCH="🌿"
|
||||
readonly TAG="🏷️"
|
||||
readonly GITHUB="⭐"
|
||||
readonly STAR="⭐"
|
||||
readonly NPM="📦"
|
||||
readonly PACKAGIST="🎯"
|
||||
|
||||
# Configuration
|
||||
readonly ORGANIZATION="php-flasher"
|
||||
readonly MAIN_BRANCH="2.x"
|
||||
readonly REPOSITORIES=(
|
||||
"flasher"
|
||||
"flasher-laravel"
|
||||
"flasher-symfony"
|
||||
"flasher-noty"
|
||||
"flasher-noty-laravel"
|
||||
"flasher-noty-symfony"
|
||||
"flasher-notyf"
|
||||
"flasher-notyf-laravel"
|
||||
"flasher-notyf-symfony"
|
||||
"flasher-sweetalert"
|
||||
"flasher-sweetalert-laravel"
|
||||
"flasher-sweetalert-symfony"
|
||||
"flasher-toastr"
|
||||
"flasher-toastr-laravel"
|
||||
"flasher-toastr-symfony"
|
||||
)
|
||||
|
||||
# Print functions
|
||||
print_header() {
|
||||
echo -e "\n${BOLD}${BLUE}╭──────────────────────────────────────────╮${RESET}"
|
||||
echo -e "${BOLD}${BLUE}│ ${ROCKET} PHP-Flasher Status ${ROCKET} │${RESET}"
|
||||
echo -e "${BOLD}${BLUE}╰──────────────────────────────────────────╯${RESET}\n"
|
||||
echo -e " ${DIM}Date : $(date -u '+%Y-%m-%d %H:%M:%S') UTC${RESET}"
|
||||
echo -e " ${DIM}User : $(whoami)${RESET}"
|
||||
echo -e " ${DIM}Directory: $(pwd)${RESET}"
|
||||
}
|
||||
|
||||
print_section() {
|
||||
echo -e "\n${BOLD}${CYAN} $1 ${2:-}${RESET}"
|
||||
}
|
||||
|
||||
warning_msg() {
|
||||
echo -e " ${YELLOW}${WARNING} $*${RESET}"
|
||||
}
|
||||
|
||||
success_msg() {
|
||||
echo -e " ${GREEN}${CHECK} $*${RESET}"
|
||||
}
|
||||
|
||||
error_msg() {
|
||||
echo -e " ${RED}${ERROR} $*${RESET}"
|
||||
}
|
||||
|
||||
info_msg() {
|
||||
echo -e "${BLUE}${INFO} $*${RESET}"
|
||||
}
|
||||
|
||||
# Get the latest tag for a repository
|
||||
get_latest_tag() {
|
||||
local repo=$1
|
||||
git ls-remote --tags --refs "git@github.com:${ORGANIZATION}/${repo}.git" |
|
||||
sort -t '/' -k 3 -V |
|
||||
tail -n1 |
|
||||
awk -F/ '{print $3}'
|
||||
}
|
||||
|
||||
# Get commit count since last tag
|
||||
get_commit_count_since_tag() {
|
||||
local repo=$1
|
||||
local tag=$2
|
||||
git rev-list "${tag}..HEAD" --count 2>/dev/null || echo "0"
|
||||
}
|
||||
|
||||
# Get repository statistics
|
||||
get_repo_stats() {
|
||||
local repo=$1
|
||||
local tmp_dir="/tmp/php-flasher-status/${repo}"
|
||||
|
||||
mkdir -p "$tmp_dir"
|
||||
if [ ! -d "$tmp_dir/.git" ]; then
|
||||
git clone -q "git@github.com:${ORGANIZATION}/${repo}.git" "$tmp_dir" 2>/dev/null
|
||||
fi
|
||||
|
||||
(
|
||||
cd "$tmp_dir"
|
||||
git fetch -q origin 2>/dev/null
|
||||
echo "$(git rev-parse --short HEAD)|$(git rev-parse --abbrev-ref HEAD)|$(git log -1 --format='%cr')|$(git log -1 --format='%s')"
|
||||
)
|
||||
}
|
||||
|
||||
# Check composer.json version
|
||||
check_composer_version() {
|
||||
local file="composer.json"
|
||||
if [ -f "$file" ]; then
|
||||
grep -o '"version": *"[^"]*"' "$file" 2>/dev/null | cut -d'"' -f4 || echo "N/A"
|
||||
else
|
||||
echo "N/A"
|
||||
fi
|
||||
}
|
||||
|
||||
# Add curl with proper user agent for API calls
|
||||
curl_cmd() {
|
||||
# You can set your GitHub token as an environment variable
|
||||
local gh_token=${GITHUB_TOKEN:-""}
|
||||
local auth_header=""
|
||||
if [ ! -z "$gh_token" ]; then
|
||||
auth_header="-H \"Authorization: token $gh_token\""
|
||||
fi
|
||||
|
||||
curl -s -H "User-Agent: PHP-Flasher-Status-Check" $auth_header "$@"
|
||||
}
|
||||
|
||||
# Get GitHub stars for a repository
|
||||
get_github_stars() {
|
||||
local repo=$1
|
||||
local response=$(curl_cmd "https://api.github.com/repos/${ORGANIZATION}/${repo}")
|
||||
local stars=$(echo "$response" | grep -o '"stargazers_count":[0-9]*' | cut -d':' -f2)
|
||||
echo "${stars:-0}"
|
||||
}
|
||||
|
||||
# Get Packagist version
|
||||
get_packagist_version() {
|
||||
local package=$1
|
||||
local response=$(curl -s -f "https://repo.packagist.org/p2/php-flasher/${package}.json")
|
||||
if [ $? -eq 0 ] && [ ! -z "$response" ]; then
|
||||
local version=$(echo "$response" | grep -o '"latest":"[^"]*"' | cut -d'"' -f4)
|
||||
if [ ! -z "$version" ]; then
|
||||
echo "$version"
|
||||
else
|
||||
echo "N/A"
|
||||
fi
|
||||
else
|
||||
echo "N/A"
|
||||
fi
|
||||
}
|
||||
|
||||
# Get NPM version
|
||||
get_npm_version() {
|
||||
local package=$1
|
||||
# Convert package name format
|
||||
if [[ "$package" == "flasher" ]]; then
|
||||
package="flasher"
|
||||
elif [[ "$package" == *"-prime" ]]; then
|
||||
# Remove -prime suffix for npm package name
|
||||
package=${package%-prime}
|
||||
elif [[ "$package" == *"-laravel" || "$package" == *"-symfony" ]]; then
|
||||
# These packages don't have npm versions
|
||||
echo "N/A"
|
||||
return
|
||||
fi
|
||||
|
||||
local response=$(curl_cmd "https://registry.npmjs.org/@flasher/${package}/latest")
|
||||
local version=$(echo "$response" | grep -o '"version":"[^"]*"' | cut -d'"' -f4)
|
||||
echo "${version:-N/A}"
|
||||
}
|
||||
|
||||
# Display repository information
|
||||
display_repo_info() {
|
||||
local repo=$1
|
||||
local latest_tag=$(get_latest_tag "$repo")
|
||||
local stats=($(get_repo_stats "$repo" | tr '|' ' '))
|
||||
local github_stars=$(get_github_stars "$repo")
|
||||
local npm_version="N/A"
|
||||
local packagist_version="N/A"
|
||||
|
||||
# Get NPM version for specific packages
|
||||
if [[ "$repo" == "flasher" || \
|
||||
"$repo" == "flasher-noty" || \
|
||||
"$repo" == "flasher-notyf" || \
|
||||
"$repo" == "flasher-sweetalert" || \
|
||||
"$repo" == "flasher-toastr" ]]; then
|
||||
npm_version=$(get_npm_version "$repo")
|
||||
fi
|
||||
|
||||
# Get Packagist version
|
||||
packagist_version=$(get_packagist_version "$repo")
|
||||
|
||||
# Display repository information
|
||||
echo -e "\n${BOLD}${MAGENTA} ${PACKAGE} ${repo}${RESET}"
|
||||
echo -e " ${BRANCH} Branch : ${stats[1]:-unknown}"
|
||||
echo -e " ${TAG} Latest Tag : ${latest_tag:-none}"
|
||||
echo -e " ${STAR} Stars : ${github_stars}"
|
||||
echo -e " ${PACKAGIST} Packagist : v${packagist_version}"
|
||||
|
||||
if [ "$npm_version" != "N/A" ]; then
|
||||
echo -e " ${NPM} NPM : v${npm_version}"
|
||||
fi
|
||||
|
||||
echo -e " ${GITHUB} Last Commit : ${stats[0]:-unknown} (${stats[2]:-unknown})"
|
||||
echo -e " ${INFO} Message : ${stats[3]:-unknown}"
|
||||
|
||||
local commits_since_tag=$(get_commit_count_since_tag "$repo" "$latest_tag")
|
||||
if [ "$commits_since_tag" -gt 0 ]; then
|
||||
warning_msg "$commits_since_tag commit(s) since last tag"
|
||||
fi
|
||||
}
|
||||
|
||||
# Check git status
|
||||
check_git_status() {
|
||||
print_section "Git Status" "${GITHUB}"
|
||||
|
||||
local current_branch=$(git rev-parse --abbrev-ref HEAD)
|
||||
echo -e " ${BRANCH} Current Branch : ${current_branch}"
|
||||
|
||||
if [ "$current_branch" != "$MAIN_BRANCH" ]; then
|
||||
warning_msg " Not on main branch ($MAIN_BRANCH)"
|
||||
fi
|
||||
|
||||
if [[ ! -z "$(git status --porcelain)" ]]; then
|
||||
warning_msg " Working directory is not clean"
|
||||
git status --short | sed 's/^/ /'
|
||||
else
|
||||
success_msg " Working directory is clean"
|
||||
fi
|
||||
|
||||
local behind=$(git rev-list HEAD..origin/$current_branch --count 2>/dev/null || echo "0")
|
||||
local ahead=$(git rev-list origin/$current_branch..HEAD --count 2>/dev/null || echo "0")
|
||||
|
||||
if [ "$behind" -gt 0 ]; then
|
||||
warning_msg " Branch is behind by $behind commit(s)"
|
||||
fi
|
||||
if [ "$ahead" -gt 0 ]; then
|
||||
warning_msg " Branch is ahead by $ahead commit(s)"
|
||||
fi
|
||||
if [ "$behind" -eq 0 ] && [ "$ahead" -eq 0 ]; then
|
||||
success_msg " Branch is up to date with origin"
|
||||
fi
|
||||
}
|
||||
|
||||
# Check dependencies
|
||||
check_dependencies() {
|
||||
print_section "Dependencies" "${PACKAGE}"
|
||||
|
||||
if [ -f "composer.json" ]; then
|
||||
echo -e " ${BOLD}Composer Dependencies:${RESET}"
|
||||
composer show | grep "php-flasher/" | sed 's/^/ /' || echo " No PHP-Flasher dependencies found"
|
||||
fi
|
||||
|
||||
if [ -f "package.json" ]; then
|
||||
echo -e "\n ${BOLD}NPM Dependencies:${RESET}"
|
||||
npm list | grep "@flasher/" | sed 's/^/ /' || echo " No Flasher dependencies found"
|
||||
fi
|
||||
}
|
||||
|
||||
# Display modified files
|
||||
display_modified_files() {
|
||||
print_section "Modified Files" "📝"
|
||||
|
||||
local modified_files=$(git diff --name-only)
|
||||
if [ ! -z "$modified_files" ]; then
|
||||
echo -e " ${BOLD}Modified files:${RESET}"
|
||||
echo "$modified_files" | sed 's/^/ /'
|
||||
else
|
||||
success_msg " No modified files"
|
||||
fi
|
||||
}
|
||||
|
||||
# Main execution
|
||||
main() {
|
||||
print_header
|
||||
|
||||
# Check current repository status
|
||||
check_git_status
|
||||
|
||||
# Check dependencies
|
||||
check_dependencies
|
||||
|
||||
# Display modified files
|
||||
display_modified_files
|
||||
|
||||
# Display repositories information
|
||||
print_section "Repositories Status" "${PACKAGE}"
|
||||
for repo in "${REPOSITORIES[@]}"; do
|
||||
display_repo_info "$repo"
|
||||
done
|
||||
|
||||
# Display release readiness
|
||||
print_section "Release Readiness" "${ROCKET}"
|
||||
local ready=true
|
||||
|
||||
if [ ! -z "$(git status --porcelain)" ]; then
|
||||
warning_msg "Working directory is not clean"
|
||||
ready=false
|
||||
fi
|
||||
|
||||
if [ "$(git rev-parse --abbrev-ref HEAD)" != "$MAIN_BRANCH" ]; then
|
||||
warning_msg "Not on main branch ($MAIN_BRANCH)"
|
||||
ready=false
|
||||
fi
|
||||
|
||||
if $ready; then
|
||||
success_msg "Ready for release!"
|
||||
echo -e "\n${BOLD}${GREEN}Suggested next steps:${RESET}"
|
||||
echo -e "1. Run: ${ITALIC}./bin/split${RESET}"
|
||||
echo -e "2. Run: ${ITALIC}./bin/release <version>${RESET}"
|
||||
else
|
||||
warning_msg "Not ready for release. Please fix the issues above."
|
||||
fi
|
||||
}
|
||||
|
||||
# Execute main function
|
||||
main
|
||||
Executable
+124
@@ -0,0 +1,124 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -o pipefail
|
||||
|
||||
# Colors and styles
|
||||
readonly RESET='\033[0m'
|
||||
readonly BOLD='\033[1m'
|
||||
readonly DIM='\033[2m'
|
||||
readonly UNDERLINE='\033[4m'
|
||||
readonly BLUE='\033[34m'
|
||||
readonly GREEN='\033[32m'
|
||||
readonly RED='\033[31m'
|
||||
readonly YELLOW='\033[33m'
|
||||
readonly CYAN='\033[36m'
|
||||
readonly MAGENTA='\033[35m'
|
||||
|
||||
# Essential emojis
|
||||
readonly ROCKET="🚀"
|
||||
readonly CHECK="✓"
|
||||
readonly ERROR="❌"
|
||||
readonly PACKAGE="📦"
|
||||
readonly SEARCH="🔍"
|
||||
readonly HAMMER="🏗️"
|
||||
readonly SPARKLES="✨"
|
||||
readonly WARNING="⚠️"
|
||||
|
||||
print_header() {
|
||||
echo -e "\n${BOLD}${BLUE}${ROCKET} PHP-Flasher Update ${ROCKET}${RESET}\n"
|
||||
echo -e "${BOLD}Date : ${RESET}${CYAN}$(date -u '+%Y-%m-%d %H:%M:%S') UTC${RESET}"
|
||||
echo -e "${BOLD}User : ${RESET}${MAGENTA}$(whoami)${RESET}"
|
||||
echo -e "${BOLD}Branch : ${RESET}${GREEN}$(git rev-parse --abbrev-ref HEAD)${RESET}"
|
||||
echo -e "${BOLD}Directory : ${RESET}${BLUE}$(pwd)${RESET}\n"
|
||||
}
|
||||
|
||||
update_composer_dependencies() {
|
||||
echo -e "${BOLD}${PACKAGE} Composer Dependencies${RESET}"
|
||||
|
||||
if composer update --prefer-lowest -W; then
|
||||
echo -e "${CHECK} ${GREEN}Dependencies updated successfully${RESET}\n"
|
||||
return 0
|
||||
else
|
||||
echo -e "${ERROR} ${RED}Failed to update Composer dependencies${RESET}\n"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
check_npm_updates() {
|
||||
echo -e "${BOLD}${SEARCH} NPM Updates Check${RESET}"
|
||||
|
||||
# Run the commands and capture their exit codes
|
||||
ncu -u
|
||||
NCU_EXIT_CODE=$?
|
||||
|
||||
npm run ncu --workspaces
|
||||
NPM_EXIT_CODE=$?
|
||||
|
||||
# Check if both commands were successful
|
||||
if [ $NCU_EXIT_CODE -eq 0 ] && [ $NPM_EXIT_CODE -eq 0 ]; then
|
||||
echo -e "${CHECK} ${GREEN}NPM check completed successfully${RESET}\n"
|
||||
else
|
||||
echo -e "${WARNING} ${YELLOW}NPM check failed, continuing...${RESET}\n"
|
||||
fi
|
||||
|
||||
return 0 # Continue regardless of outcome
|
||||
}
|
||||
|
||||
update_npm_dependencies() {
|
||||
echo -e "${BOLD}${PACKAGE} NPM Dependencies${RESET}"
|
||||
|
||||
if npm install --force; then
|
||||
echo -e "${CHECK} ${GREEN}NPM dependencies installed successfully${RESET}\n"
|
||||
return 0
|
||||
else
|
||||
echo -e "${WARNING} ${YELLOW}NPM install failed, continuing...${RESET}\n"
|
||||
return 0 # Continue despite failure
|
||||
fi
|
||||
}
|
||||
|
||||
build_assets() {
|
||||
echo -e "${BOLD}${HAMMER} Building Assets${RESET}"
|
||||
|
||||
if npm run build; then
|
||||
echo -e "${CHECK} ${GREEN}Assets built successfully${RESET}\n"
|
||||
return 0
|
||||
else
|
||||
echo -e "${WARNING} ${YELLOW}Build failed, continuing...${RESET}\n"
|
||||
return 0 # Continue despite failure
|
||||
fi
|
||||
}
|
||||
|
||||
main() {
|
||||
local start_time=$(date +%s)
|
||||
local success=true
|
||||
|
||||
print_header
|
||||
|
||||
# Update composer dependencies
|
||||
update_composer_dependencies || success=false
|
||||
|
||||
# Check NPM updates
|
||||
check_npm_updates
|
||||
|
||||
# Update NPM dependencies
|
||||
update_npm_dependencies
|
||||
|
||||
# Build assets
|
||||
build_assets
|
||||
|
||||
local end_time=$(date +%s)
|
||||
local duration=$((end_time - start_time))
|
||||
|
||||
# Summary
|
||||
echo -e "${BOLD}${CYAN}Update Summary${RESET}"
|
||||
if [ "$success" = true ]; then
|
||||
echo -e "${SPARKLES} ${GREEN}Update completed successfully${RESET}"
|
||||
else
|
||||
echo -e "${WARNING} ${YELLOW}Update completed with some issues${RESET}"
|
||||
fi
|
||||
echo -e "Duration : ${YELLOW}${duration}s${RESET}\n"
|
||||
|
||||
[ "$success" = true ] && exit 0 || exit 1
|
||||
}
|
||||
|
||||
main
|
||||
+12
-13
@@ -22,21 +22,21 @@
|
||||
"require": {
|
||||
"php": ">=8.2",
|
||||
"ext-intl": "*",
|
||||
"illuminate/contracts": "^11.0|^12.0",
|
||||
"illuminate/routing": "^11.0|^12.0",
|
||||
"illuminate/support": "^11.0|^12.0",
|
||||
"illuminate/contracts": "^11.0|^12.0|^13.0",
|
||||
"illuminate/routing": "^11.0|^12.0|^13.0",
|
||||
"illuminate/support": "^11.0|^12.0|^13.0",
|
||||
"laravel/octane": "^2.3",
|
||||
"livewire/livewire": "^3.0",
|
||||
"paragonie/random_compat": "^2.0",
|
||||
"psr/container": "^1.1|^2.0",
|
||||
"symfony/config": "^7.0",
|
||||
"symfony/console": "^7.0",
|
||||
"symfony/dependency-injection": "^7.0",
|
||||
"symfony/framework-bundle": "^7.0",
|
||||
"symfony/http-kernel": "^7.0",
|
||||
"symfony/translation": "^7.0",
|
||||
"symfony/twig-bundle": "^7.0",
|
||||
"symfony/ux-twig-component": "^2.19"
|
||||
"symfony/config": "^7.0|^8.0",
|
||||
"symfony/console": "^7.0|^8.0",
|
||||
"symfony/dependency-injection": "^7.0|^8.0",
|
||||
"symfony/framework-bundle": "^7.0|^8.0",
|
||||
"symfony/http-kernel": "^7.0|^8.0",
|
||||
"symfony/translation": "^7.0|^8.0",
|
||||
"symfony/twig-bundle": "^7.0|^8.0",
|
||||
"symfony/ux-twig-component": "^2.19",
|
||||
"yoeunes/regex-parser": "^1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"larastan/larastan": "^2.9.9",
|
||||
@@ -51,7 +51,6 @@
|
||||
"phpunit/phpunit": "^10.5.26",
|
||||
"rector/rector": "^1.2.8",
|
||||
"rector/swiss-knife": "^1.0.0",
|
||||
"spatie/ray": "^1.41.2",
|
||||
"symplify/monorepo-builder": "^11.2.22"
|
||||
},
|
||||
"autoload": {
|
||||
|
||||
Generated
+969
-551
File diff suppressed because it is too large
Load Diff
@@ -1 +1 @@
|
||||
8.2
|
||||
8.3
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class DashboardController extends Controller
|
||||
{
|
||||
/**
|
||||
* Show the dashboard with overview of PHPFlasher features
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
flash()->option('timeout', 10000)
|
||||
->info('Welcome to the PHPFlasher Laravel Demo! 👋 Explore different examples using the navigation.');
|
||||
|
||||
return view('dashboard');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show all notification types at once
|
||||
*/
|
||||
public function showAllTypes()
|
||||
{
|
||||
flash()->success('This is a success notification!');
|
||||
flash()->info('This is an information notification!');
|
||||
flash()->warning('This is a warning notification!');
|
||||
flash()->error('This is an error notification!');
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show theme selector
|
||||
*/
|
||||
public function themeSelector()
|
||||
{
|
||||
return view('features.themes');
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a notification with the selected theme
|
||||
*/
|
||||
public function showTheme(Request $request)
|
||||
{
|
||||
$theme = $request->input('theme', 'default');
|
||||
|
||||
flash()
|
||||
->use("theme.$theme")
|
||||
->success("This notification uses the '$theme' theme!");
|
||||
|
||||
return redirect()->route('themes');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\View\View;
|
||||
|
||||
final class DemoController extends Controller
|
||||
{
|
||||
public function home(): View
|
||||
{
|
||||
return view('home');
|
||||
}
|
||||
|
||||
public function types(): View
|
||||
{
|
||||
return view('types');
|
||||
}
|
||||
|
||||
public function themes(): View
|
||||
{
|
||||
return view('themes');
|
||||
}
|
||||
|
||||
public function adapters(): View
|
||||
{
|
||||
return view('adapters');
|
||||
}
|
||||
|
||||
public function positions(): View
|
||||
{
|
||||
return view('positions');
|
||||
}
|
||||
|
||||
public function examples(): View
|
||||
{
|
||||
return view('examples');
|
||||
}
|
||||
|
||||
public function playground(): View
|
||||
{
|
||||
return view('playground');
|
||||
}
|
||||
|
||||
public function livewire(): View
|
||||
{
|
||||
return view('livewire');
|
||||
}
|
||||
|
||||
public function notify(Request $request): JsonResponse
|
||||
{
|
||||
$type = $request->input('type', 'success');
|
||||
$message = $request->input('message', 'Notification message');
|
||||
$title = $request->input('title');
|
||||
$theme = $request->input('theme');
|
||||
$position = $request->input('position', 'top-right');
|
||||
$timeout = (int) $request->input('timeout', 5000);
|
||||
|
||||
$flasher = flash();
|
||||
|
||||
// Apply theme if specified
|
||||
if ($theme && $theme !== 'flasher') {
|
||||
$flasher = $flasher->use("theme.{$theme}");
|
||||
}
|
||||
|
||||
$options = [
|
||||
'position' => $position,
|
||||
'timeout' => $timeout,
|
||||
];
|
||||
|
||||
if ($title) {
|
||||
$options['title'] = $title;
|
||||
}
|
||||
|
||||
$flasher->{$type}($message, $options);
|
||||
|
||||
return response()->json(['success' => true]);
|
||||
}
|
||||
|
||||
public function runExample(Request $request, string $scenario): JsonResponse
|
||||
{
|
||||
match ($scenario) {
|
||||
'registration' => $this->registrationExample(),
|
||||
'login_failed' => $this->loginFailedExample(),
|
||||
'validation' => $this->validationExample(),
|
||||
'shopping_cart' => $this->shoppingCartExample(),
|
||||
'file_upload' => $this->fileUploadExample(),
|
||||
'settings' => $this->settingsExample(),
|
||||
'payment_success' => $this->paymentSuccessExample(),
|
||||
'payment_failed' => $this->paymentFailedExample(),
|
||||
'delete_confirm' => $this->deleteConfirmExample(),
|
||||
'session_expiring' => $this->sessionExpiringExample(),
|
||||
default => flash()->info('Example not found'),
|
||||
};
|
||||
|
||||
return response()->json(['success' => true]);
|
||||
}
|
||||
|
||||
private function registrationExample(): void
|
||||
{
|
||||
flash()->success('Welcome! Your account has been created.');
|
||||
flash()->info('Please check your email to verify your account.');
|
||||
}
|
||||
|
||||
private function loginFailedExample(): void
|
||||
{
|
||||
flash()->error('Invalid email or password.');
|
||||
flash()->info('Forgot your password? Click here to reset.');
|
||||
}
|
||||
|
||||
private function validationExample(): void
|
||||
{
|
||||
flash()->error('The email field is required.');
|
||||
flash()->error('Password must be at least 8 characters.');
|
||||
flash()->error('Please accept the terms and conditions.');
|
||||
}
|
||||
|
||||
private function shoppingCartExample(): void
|
||||
{
|
||||
flash()->success('iPhone 15 Pro added to cart!');
|
||||
flash()->warning('Only 2 items left in stock!');
|
||||
flash()->info('Add $20 more for free shipping!');
|
||||
}
|
||||
|
||||
private function fileUploadExample(): void
|
||||
{
|
||||
flash()->success('document.pdf uploaded successfully!');
|
||||
flash()->info('File size: 2.4 MB');
|
||||
}
|
||||
|
||||
private function settingsExample(): void
|
||||
{
|
||||
flash()->success('Settings saved successfully!');
|
||||
flash()->info('Some changes may require a page refresh.');
|
||||
}
|
||||
|
||||
private function paymentSuccessExample(): void
|
||||
{
|
||||
flash()->success('Payment of $149.99 confirmed!');
|
||||
flash()->info('Order #12345 - Receipt sent to your email.');
|
||||
}
|
||||
|
||||
private function paymentFailedExample(): void
|
||||
{
|
||||
flash()->error('Payment declined by your bank.');
|
||||
flash()->warning('Please try a different payment method.');
|
||||
flash()->info('Your cart has been saved.');
|
||||
}
|
||||
|
||||
private function deleteConfirmExample(): void
|
||||
{
|
||||
flash()->warning('Are you sure? This action cannot be undone.');
|
||||
flash()->info('Click confirm to delete or cancel to keep the item.');
|
||||
}
|
||||
|
||||
private function sessionExpiringExample(): void
|
||||
{
|
||||
flash()->warning('Your session will expire in 5 minutes.');
|
||||
flash()->info('Click anywhere to stay logged in.');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
|
||||
class ExampleController extends Controller
|
||||
{
|
||||
/**
|
||||
* Form validation example
|
||||
*/
|
||||
public function formExample()
|
||||
{
|
||||
return view('examples.form');
|
||||
}
|
||||
|
||||
/**
|
||||
* Process form submission
|
||||
*/
|
||||
public function processForm(Request $request)
|
||||
{
|
||||
$validator = Validator::make($request->all(), [
|
||||
'name' => 'required|min:2|max:50',
|
||||
'email' => 'required|email',
|
||||
'subject' => 'required|min:5',
|
||||
'message' => 'required|min:10',
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
flash()->error('Please fix the errors in the form!');
|
||||
return redirect()->back()
|
||||
->withErrors($validator)
|
||||
->withInput();
|
||||
}
|
||||
|
||||
// Success scenario
|
||||
flash()
|
||||
->success('Your message has been sent successfully!')
|
||||
->option('timeout', 8000);
|
||||
|
||||
return redirect()->route('form.example');
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX example page
|
||||
*/
|
||||
public function ajaxExample()
|
||||
{
|
||||
return view('examples.ajax');
|
||||
}
|
||||
|
||||
/**
|
||||
* Process AJAX request
|
||||
*/
|
||||
public function processAjax(Request $request)
|
||||
{
|
||||
$action = $request->input('action');
|
||||
$success = rand(0, 10) > 3; // 70% success rate
|
||||
|
||||
if ($success) {
|
||||
flash()->success("The $action action was completed successfully!");
|
||||
return response()->json(['status' => 'success']);
|
||||
} else {
|
||||
flash()->error("The $action action failed. Please try again.");
|
||||
return response()->json(['status' => 'error'], 422);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Demonstrate different notification positions
|
||||
*/
|
||||
public function positionsExample()
|
||||
{
|
||||
return view('examples.positions');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show notification at specified position
|
||||
*/
|
||||
public function showAtPosition(Request $request)
|
||||
{
|
||||
$position = $request->input('position', 'top-right');
|
||||
|
||||
flash()
|
||||
->option('position', $position)
|
||||
->info("This notification appears at the '$position' position!");
|
||||
|
||||
return redirect()->route('positions.example');
|
||||
}
|
||||
|
||||
/**
|
||||
* Interactive playground to test notification options
|
||||
*/
|
||||
public function playground()
|
||||
{
|
||||
return view('examples.playground');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Livewire;
|
||||
|
||||
use Livewire\Component;
|
||||
|
||||
class ContactForm extends Component
|
||||
{
|
||||
public string $name = '';
|
||||
public string $email = '';
|
||||
public string $message = '';
|
||||
|
||||
protected array $rules = [
|
||||
'name' => 'required|min:2',
|
||||
'email' => 'required|email',
|
||||
'message' => 'required|min:10',
|
||||
];
|
||||
|
||||
public function submit(): void
|
||||
{
|
||||
$this->validate();
|
||||
|
||||
// Simulate form processing
|
||||
flash()->success('Message sent successfully!');
|
||||
flash()->info('We will respond within 24 hours.');
|
||||
|
||||
$this->reset(['name', 'email', 'message']);
|
||||
}
|
||||
|
||||
public function render()
|
||||
{
|
||||
return view('livewire.contact-form');
|
||||
}
|
||||
}
|
||||
@@ -1,25 +1,31 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Livewire;
|
||||
|
||||
use Livewire\Component;
|
||||
|
||||
class Counter extends Component
|
||||
{
|
||||
public $count = 1;
|
||||
public int $count = 0;
|
||||
|
||||
public function increment()
|
||||
public function increment(): void
|
||||
{
|
||||
flash()->success('increment');
|
||||
|
||||
$this->count++;
|
||||
flash()->success("Count increased to {$this->count}!");
|
||||
}
|
||||
|
||||
public function decrement()
|
||||
public function decrement(): void
|
||||
{
|
||||
flash()->info('decrement');
|
||||
|
||||
$this->count--;
|
||||
flash()->warning("Count decreased to {$this->count}");
|
||||
}
|
||||
|
||||
public function reset(): void
|
||||
{
|
||||
$this->count = 0;
|
||||
flash()->info('Counter has been reset.');
|
||||
}
|
||||
|
||||
public function render()
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Livewire;
|
||||
|
||||
use Livewire\Component;
|
||||
|
||||
class DeleteItem extends Component
|
||||
{
|
||||
protected $listeners = [
|
||||
'sweetalert:confirmed' => 'onConfirmed',
|
||||
'sweetalert:denied' => 'onDenied',
|
||||
];
|
||||
|
||||
public function confirmDelete(): void
|
||||
{
|
||||
sweetalert()
|
||||
->showDenyButton()
|
||||
->showCancelButton()
|
||||
->confirmButtonText('Yes, delete it!')
|
||||
->denyButtonText('Keep it')
|
||||
->warning('Are you sure you want to delete this item?');
|
||||
}
|
||||
|
||||
public function onConfirmed(array $payload): void
|
||||
{
|
||||
// Simulate deletion
|
||||
flash()->success('Item has been deleted successfully!');
|
||||
}
|
||||
|
||||
public function onDenied(array $payload): void
|
||||
{
|
||||
flash()->info('The item was kept safe.');
|
||||
}
|
||||
|
||||
public function render()
|
||||
{
|
||||
return view('livewire.delete-item');
|
||||
}
|
||||
}
|
||||
+19
-19
@@ -14,27 +14,27 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": "^8.2",
|
||||
"inertiajs/inertia-laravel": "^2.0.1",
|
||||
"laravel/framework": "^11.43.2",
|
||||
"laravel/tinker": "^2.10.1",
|
||||
"livewire/livewire": "^3.5.20",
|
||||
"php": "^8.3",
|
||||
"inertiajs/inertia-laravel": "^2.0",
|
||||
"laravel/framework": "^13.0",
|
||||
"laravel/tinker": "^3.0",
|
||||
"livewire/livewire": "^3.6",
|
||||
"php-flasher/php-flasher": "@dev",
|
||||
"spatie/laravel-csp": "^2.10.3",
|
||||
"spatie/laravel-ray": "^1.39.1"
|
||||
"spatie/laravel-csp": "^3.23",
|
||||
"spatie/laravel-ray": "^1.40"
|
||||
},
|
||||
"require-dev": {
|
||||
"barryvdh/laravel-debugbar": "^3.15",
|
||||
"fakerphp/faker": "^1.24.1",
|
||||
"larastan/larastan": "^3.1",
|
||||
"barryvdh/laravel-debugbar": "^4.1",
|
||||
"fakerphp/faker": "^1.24",
|
||||
"larastan/larastan": "^3.2",
|
||||
"laravel/pint": "^1.21",
|
||||
"laravel/sail": "^1.41",
|
||||
"mockery/mockery": "^1.6.12",
|
||||
"nunomaduro/collision": "^8.6.1",
|
||||
"pestphp/pest": "^3.7.4",
|
||||
"pestphp/pest-plugin-laravel": "^3.1",
|
||||
"spatie/laravel-ignition": "^2.9.1",
|
||||
"spatie/ray": "^1.41.5"
|
||||
"mockery/mockery": "^1.6",
|
||||
"nunomaduro/collision": "^8.7",
|
||||
"pestphp/pest": "^4.0",
|
||||
"pestphp/pest-plugin-laravel": "^4.0",
|
||||
"spatie/laravel-ignition": "^2.9",
|
||||
"spatie/ray": "^1.41"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
@@ -52,15 +52,15 @@
|
||||
"post-autoload-dump": [
|
||||
"Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
|
||||
"@php artisan package:discover --ansi",
|
||||
"@php artisan flasher:install --symlink"
|
||||
"@php artisan flasher:install"
|
||||
],
|
||||
"post-update-cmd": [
|
||||
"@php artisan vendor:publish --tag=laravel-assets --ansi --force",
|
||||
"@php artisan flasher:install --symlink"
|
||||
"@php artisan flasher:install"
|
||||
],
|
||||
"post-root-package-install": [
|
||||
"@php -r \"file_exists('.env') || copy('.env.example', '.env');\"",
|
||||
"@php artisan flasher:install --symlink"
|
||||
"@php artisan flasher:install"
|
||||
],
|
||||
"post-create-project-cmd": [
|
||||
"@php artisan key:generate --ansi",
|
||||
|
||||
Generated
+2449
-1869
File diff suppressed because it is too large
Load Diff
@@ -1,14 +1,64 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
declare(strict_types=1);
|
||||
|
||||
use Flasher\Prime\Configuration;
|
||||
|
||||
/*
|
||||
* Default PHPFlasher configuration for Laravel.
|
||||
*
|
||||
* This configuration file defines the default settings for PHPFlasher when
|
||||
* used within a Laravel application. It uses the Configuration class from
|
||||
* the core PHPFlasher library to establish type-safe configuration.
|
||||
*
|
||||
* @return array<string, mixed> PHPFlasher configuration
|
||||
*/
|
||||
return Configuration::from([
|
||||
// Default notification library (e.g., 'flasher', 'toastr', 'noty', 'notyf', 'sweetalert')
|
||||
'default' => 'flasher',
|
||||
|
||||
// Path to the main PHPFlasher JavaScript file
|
||||
'main_script' => '/vendor/flasher/flasher.min.js',
|
||||
|
||||
// List of CSS files to style your notifications
|
||||
'styles' => [
|
||||
'/vendor/flasher/flasher.min.css',
|
||||
],
|
||||
|
||||
// Set global options for all notifications (optional)
|
||||
// 'options' => [
|
||||
// 'timeout' => 5000, // Time in milliseconds before the notification disappears
|
||||
// 'position' => 'top-right', // Where the notification appears on the screen
|
||||
// ],
|
||||
|
||||
// Automatically inject JavaScript and CSS assets into your HTML pages
|
||||
'inject_assets' => true,
|
||||
|
||||
'options' => [
|
||||
'timeout' => 5000, // in milliseconds
|
||||
'position' => 'top-right',
|
||||
// Enable message translation using Laravel's translation service
|
||||
'translate' => true,
|
||||
|
||||
// URL patterns to exclude from asset injection and flash_bag conversion
|
||||
'excluded_paths' => [],
|
||||
|
||||
// Map Laravel flash message keys to notification types
|
||||
'flash_bag' => [
|
||||
'success' => ['success'],
|
||||
'error' => ['error', 'danger'],
|
||||
'warning' => ['warning', 'alarm'],
|
||||
'info' => ['info', 'notice', 'alert'],
|
||||
],
|
||||
|
||||
'flash_bag' => [
|
||||
'success' => ['success', 'ok', 'completed', 'passed', 'achieved'],
|
||||
],
|
||||
];
|
||||
// Set criteria to filter which notifications are displayed (optional)
|
||||
// 'filter' => [
|
||||
// 'limit' => 5, // Maximum number of notifications to show at once
|
||||
// ],
|
||||
|
||||
// Define notification presets to simplify notification creation (optional)
|
||||
// 'presets' => [
|
||||
// 'entity_saved' => [
|
||||
// 'type' => 'success',
|
||||
// 'title' => 'Entity saved',
|
||||
// 'message' => 'Entity saved successfully',
|
||||
// ],
|
||||
// ],
|
||||
]);
|
||||
|
||||
@@ -49,6 +49,19 @@ return [
|
||||
|
||||
'encrypt' => env('SESSION_ENCRYPT', false),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Session Serialization
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This option determines how session data is serialized before being stored.
|
||||
| The "json" driver is more secure and performant but cannot serialize
|
||||
| PHP objects. The "php" driver uses PHP's native serialization.
|
||||
|
|
||||
*/
|
||||
|
||||
'serialization' => env('SESSION_SERIALIZATION', 'json'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Session File Location
|
||||
|
||||
Generated
+1371
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,4 @@
|
||||
/* PHPFlasher Laravel Demo - Custom Styles */
|
||||
|
||||
/* Any custom styles can be added here */
|
||||
/* Note: Main styling is handled via Tailwind CSS v4 CDN in the layout */
|
||||
|
||||
@@ -1 +1,11 @@
|
||||
/**
|
||||
* PHPFlasher Laravel Demo
|
||||
*
|
||||
* Main JavaScript entry point.
|
||||
* Note: PHPFlasher and other libraries are loaded via CDN in the layout.
|
||||
*/
|
||||
|
||||
import './bootstrap';
|
||||
|
||||
// Custom demo functionality can be added here
|
||||
console.log('PHPFlasher Laravel Demo loaded');
|
||||
|
||||
@@ -0,0 +1,354 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Adapters')
|
||||
|
||||
@section('content')
|
||||
<div class="mb-8">
|
||||
<h1 class="section-title">Notification Adapters</h1>
|
||||
<p class="section-subtitle">PHPFlasher supports multiple notification libraries. Choose your favorite!</p>
|
||||
</div>
|
||||
|
||||
<div class="space-y-8">
|
||||
{{-- Flasher (Default) --}}
|
||||
<div class="card">
|
||||
<div class="h-2 bg-gradient-to-r from-indigo-500 to-purple-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex flex-col lg:flex-row lg:items-start lg:justify-between gap-6">
|
||||
<div class="flex-1">
|
||||
<div class="flex items-center space-x-3 mb-4">
|
||||
<div class="p-3 bg-indigo-100 rounded-xl">
|
||||
<svg class="w-8 h-8 text-indigo-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="text-2xl font-bold text-gray-800">Flasher</h2>
|
||||
<p class="text-gray-500">Default adapter with 17+ themes</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 mb-4">The default PHPFlasher adapter with beautiful built-in themes. No additional JavaScript libraries required.</p>
|
||||
|
||||
<div class="flex flex-wrap gap-2 mb-6">
|
||||
<button onclick="showNotification({type: 'success', message: 'This is the default Flasher notification!', adapter: 'flasher'})"
|
||||
class="btn btn-success">Success</button>
|
||||
<button onclick="showNotification({type: 'error', message: 'Error notification with Flasher', adapter: 'flasher'})"
|
||||
class="btn btn-danger">Error</button>
|
||||
<button onclick="showNotification({type: 'warning', message: 'Warning notification with Flasher', adapter: 'flasher'})"
|
||||
class="btn btn-warning">Warning</button>
|
||||
<button onclick="showNotification({type: 'info', message: 'Info notification with Flasher', adapter: 'flasher'})"
|
||||
class="btn btn-info">Info</button>
|
||||
</div>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>Installation</span>
|
||||
</div>
|
||||
<pre class="!m-0"><code class="language-bash">composer require php-flasher/flasher-laravel</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>Usage</span>
|
||||
</div>
|
||||
<pre class="!m-0"><code class="language-php">flash()->success('Operation completed!');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Toastr --}}
|
||||
<div class="card">
|
||||
<div class="h-2 bg-gradient-to-r from-sky-500 to-blue-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex flex-col lg:flex-row lg:items-start lg:justify-between gap-6">
|
||||
<div class="flex-1">
|
||||
<div class="flex items-center space-x-3 mb-4">
|
||||
<div class="p-3 bg-sky-100 rounded-xl">
|
||||
<svg class="w-8 h-8 text-sky-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="text-2xl font-bold text-gray-800">Toastr</h2>
|
||||
<p class="text-gray-500">Simple, elegant toast notifications</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 mb-4">Classic toast notifications with smooth animations. One of the most popular notification libraries.</p>
|
||||
|
||||
<div class="flex flex-wrap gap-2 mb-6">
|
||||
<button onclick="showNotification({type: 'success', message: 'Toastr success notification!', adapter: 'toastr'})"
|
||||
class="btn btn-success">Success</button>
|
||||
<button onclick="showNotification({type: 'error', message: 'Toastr error notification!', adapter: 'toastr'})"
|
||||
class="btn btn-danger">Error</button>
|
||||
<button onclick="showNotification({type: 'warning', message: 'Toastr warning notification!', adapter: 'toastr'})"
|
||||
class="btn btn-warning">Warning</button>
|
||||
<button onclick="showNotification({type: 'info', message: 'Toastr info notification!', adapter: 'toastr'})"
|
||||
class="btn btn-info">Info</button>
|
||||
</div>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>Installation</span>
|
||||
</div>
|
||||
<pre class="!m-0"><code class="language-bash">composer require php-flasher/flasher-toastr-laravel</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>Usage</span>
|
||||
</div>
|
||||
<pre class="!m-0"><code class="language-php">toastr()->success('Data saved successfully!');
|
||||
|
||||
// With options
|
||||
toastr()
|
||||
->closeButton()
|
||||
->progressBar()
|
||||
->positionClass('toast-top-right')
|
||||
->success('Profile updated!');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- SweetAlert --}}
|
||||
<div class="card">
|
||||
<div class="h-2 bg-gradient-to-r from-pink-500 to-rose-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex flex-col lg:flex-row lg:items-start lg:justify-between gap-6">
|
||||
<div class="flex-1">
|
||||
<div class="flex items-center space-x-3 mb-4">
|
||||
<div class="p-3 bg-pink-100 rounded-xl">
|
||||
<svg class="w-8 h-8 text-pink-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="text-2xl font-bold text-gray-800">SweetAlert 2</h2>
|
||||
<p class="text-gray-500">Beautiful, responsive, customizable alerts</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 mb-4">Feature-rich modal dialogs with confirmations, inputs, and beautiful animations. Perfect for important user interactions.</p>
|
||||
|
||||
<div class="flex flex-wrap gap-2 mb-6">
|
||||
<button onclick="showNotification({type: 'success', message: 'SweetAlert success!', title: 'Success', adapter: 'sweetalert'})"
|
||||
class="btn btn-success">Success</button>
|
||||
<button onclick="showNotification({type: 'error', message: 'SweetAlert error message', title: 'Error', adapter: 'sweetalert'})"
|
||||
class="btn btn-danger">Error</button>
|
||||
<button onclick="showNotification({type: 'warning', message: 'Are you sure you want to proceed?', title: 'Warning', adapter: 'sweetalert', options: {showCancelButton: true}})"
|
||||
class="btn btn-warning">Confirm Dialog</button>
|
||||
<button onclick="showNotification({type: 'info', message: 'Here is some information', title: 'Info', adapter: 'sweetalert'})"
|
||||
class="btn btn-info">Info</button>
|
||||
</div>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>Installation</span>
|
||||
</div>
|
||||
<pre class="!m-0"><code class="language-bash">composer require php-flasher/flasher-sweetalert-laravel</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>Usage</span>
|
||||
</div>
|
||||
<pre class="!m-0"><code class="language-php">sweetalert()->success('Great job!', 'Success');
|
||||
|
||||
// Confirmation dialog
|
||||
sweetalert()
|
||||
->showDenyButton()
|
||||
->showCancelButton()
|
||||
->confirmButtonText('Save')
|
||||
->denyButtonText("Don't save")
|
||||
->warning('Do you want to save the changes?');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Noty --}}
|
||||
<div class="card">
|
||||
<div class="h-2 bg-gradient-to-r from-emerald-500 to-teal-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex flex-col lg:flex-row lg:items-start lg:justify-between gap-6">
|
||||
<div class="flex-1">
|
||||
<div class="flex items-center space-x-3 mb-4">
|
||||
<div class="p-3 bg-emerald-100 rounded-xl">
|
||||
<svg class="w-8 h-8 text-emerald-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="text-2xl font-bold text-gray-800">Noty</h2>
|
||||
<p class="text-gray-500">Dependency-free notification library</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 mb-4">A flexible, dependency-free notification library with multiple layouts and themes.</p>
|
||||
|
||||
<div class="flex flex-wrap gap-2 mb-6">
|
||||
<button onclick="showNotification({type: 'success', message: 'Noty success notification!', adapter: 'noty'})"
|
||||
class="btn btn-success">Success</button>
|
||||
<button onclick="showNotification({type: 'error', message: 'Noty error notification!', adapter: 'noty'})"
|
||||
class="btn btn-danger">Error</button>
|
||||
<button onclick="showNotification({type: 'warning', message: 'Noty warning notification!', adapter: 'noty'})"
|
||||
class="btn btn-warning">Warning</button>
|
||||
<button onclick="showNotification({type: 'info', message: 'Noty info notification!', adapter: 'noty'})"
|
||||
class="btn btn-info">Info</button>
|
||||
</div>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>Installation</span>
|
||||
</div>
|
||||
<pre class="!m-0"><code class="language-bash">composer require php-flasher/flasher-noty-laravel</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>Usage</span>
|
||||
</div>
|
||||
<pre class="!m-0"><code class="language-php">noty()->success('Data saved!');
|
||||
|
||||
// With layout options
|
||||
noty()
|
||||
->layout('topCenter')
|
||||
->timeout(3000)
|
||||
->progressBar()
|
||||
->info('Processing your request...');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Notyf --}}
|
||||
<div class="card">
|
||||
<div class="h-2 bg-gradient-to-r from-amber-500 to-orange-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex flex-col lg:flex-row lg:items-start lg:justify-between gap-6">
|
||||
<div class="flex-1">
|
||||
<div class="flex items-center space-x-3 mb-4">
|
||||
<div class="p-3 bg-amber-100 rounded-xl">
|
||||
<svg class="w-8 h-8 text-amber-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 7h8m0 0v8m0-8l-8 8-4-4-6 6"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="text-2xl font-bold text-gray-800">Notyf</h2>
|
||||
<p class="text-gray-500">Minimalist, responsive notifications</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 mb-4">A minimalist JavaScript library for toast notifications. Tiny footprint with smooth animations.</p>
|
||||
|
||||
<div class="flex flex-wrap gap-2 mb-6">
|
||||
<button onclick="showNotification({type: 'success', message: 'Notyf success notification!', adapter: 'notyf'})"
|
||||
class="btn btn-success">Success</button>
|
||||
<button onclick="showNotification({type: 'error', message: 'Notyf error notification!', adapter: 'notyf'})"
|
||||
class="btn btn-danger">Error</button>
|
||||
</div>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>Installation</span>
|
||||
</div>
|
||||
<pre class="!m-0"><code class="language-bash">composer require php-flasher/flasher-notyf-laravel</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>Usage</span>
|
||||
</div>
|
||||
<pre class="!m-0"><code class="language-php">notyf()->success('Minimal and clean!');
|
||||
|
||||
// With options
|
||||
notyf()
|
||||
->position('x', 'right')
|
||||
->position('y', 'top')
|
||||
->dismissible(true)
|
||||
->ripple(true)
|
||||
->success('File uploaded successfully!');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Comparison Table --}}
|
||||
<div class="card mt-8">
|
||||
<div class="card-header">
|
||||
<h2 class="text-xl font-bold text-gray-800">Adapter Comparison</h2>
|
||||
</div>
|
||||
<div class="card-body overflow-x-auto">
|
||||
<table class="w-full text-left">
|
||||
<thead>
|
||||
<tr class="border-b border-gray-200">
|
||||
<th class="py-3 px-4 font-semibold text-gray-700">Feature</th>
|
||||
<th class="py-3 px-4 font-semibold text-gray-700">Flasher</th>
|
||||
<th class="py-3 px-4 font-semibold text-gray-700">Toastr</th>
|
||||
<th class="py-3 px-4 font-semibold text-gray-700">SweetAlert</th>
|
||||
<th class="py-3 px-4 font-semibold text-gray-700">Noty</th>
|
||||
<th class="py-3 px-4 font-semibold text-gray-700">Notyf</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="text-gray-600">
|
||||
<tr class="border-b border-gray-100">
|
||||
<td class="py-3 px-4">Toast Notifications</td>
|
||||
<td class="py-3 px-4 text-emerald-600">Yes</td>
|
||||
<td class="py-3 px-4 text-emerald-600">Yes</td>
|
||||
<td class="py-3 px-4 text-emerald-600">Yes</td>
|
||||
<td class="py-3 px-4 text-emerald-600">Yes</td>
|
||||
<td class="py-3 px-4 text-emerald-600">Yes</td>
|
||||
</tr>
|
||||
<tr class="border-b border-gray-100">
|
||||
<td class="py-3 px-4">Modal Dialogs</td>
|
||||
<td class="py-3 px-4 text-gray-400">No</td>
|
||||
<td class="py-3 px-4 text-gray-400">No</td>
|
||||
<td class="py-3 px-4 text-emerald-600">Yes</td>
|
||||
<td class="py-3 px-4 text-gray-400">No</td>
|
||||
<td class="py-3 px-4 text-gray-400">No</td>
|
||||
</tr>
|
||||
<tr class="border-b border-gray-100">
|
||||
<td class="py-3 px-4">Confirmations</td>
|
||||
<td class="py-3 px-4 text-gray-400">No</td>
|
||||
<td class="py-3 px-4 text-gray-400">No</td>
|
||||
<td class="py-3 px-4 text-emerald-600">Yes</td>
|
||||
<td class="py-3 px-4 text-emerald-600">Yes</td>
|
||||
<td class="py-3 px-4 text-gray-400">No</td>
|
||||
</tr>
|
||||
<tr class="border-b border-gray-100">
|
||||
<td class="py-3 px-4">Progress Bar</td>
|
||||
<td class="py-3 px-4 text-emerald-600">Yes</td>
|
||||
<td class="py-3 px-4 text-emerald-600">Yes</td>
|
||||
<td class="py-3 px-4 text-emerald-600">Yes</td>
|
||||
<td class="py-3 px-4 text-emerald-600">Yes</td>
|
||||
<td class="py-3 px-4 text-gray-400">No</td>
|
||||
</tr>
|
||||
<tr class="border-b border-gray-100">
|
||||
<td class="py-3 px-4">Built-in Themes</td>
|
||||
<td class="py-3 px-4 text-emerald-600">17+</td>
|
||||
<td class="py-3 px-4 text-emerald-600">4</td>
|
||||
<td class="py-3 px-4 text-emerald-600">1</td>
|
||||
<td class="py-3 px-4 text-emerald-600">5</td>
|
||||
<td class="py-3 px-4 text-emerald-600">1</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="py-3 px-4">Dependencies</td>
|
||||
<td class="py-3 px-4">None</td>
|
||||
<td class="py-3 px-4">jQuery</td>
|
||||
<td class="py-3 px-4">None</td>
|
||||
<td class="py-3 px-4">None</td>
|
||||
<td class="py-3 px-4">None</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,83 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'PHPFlasher Laravel Demo')
|
||||
|
||||
@section('content')
|
||||
<div class="max-w-7xl mx-auto">
|
||||
<div class="bg-white rounded-xl shadow-md overflow-hidden">
|
||||
<div class="p-8">
|
||||
<div class="uppercase tracking-wide text-sm text-indigo-600 font-semibold">Laravel Demo</div>
|
||||
<h2 class="mt-2 text-3xl font-extrabold tracking-tight text-gray-900">Welcome to PHPFlasher</h2>
|
||||
<p class="mt-4 text-lg text-gray-500">
|
||||
PHPFlasher is a powerful notification library for PHP applications.
|
||||
This demo shows how to use PHPFlasher in a Laravel project.
|
||||
</p>
|
||||
|
||||
<div class="mt-8 grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3">
|
||||
<!-- Feature Cards -->
|
||||
<div class="bg-indigo-50 p-6 rounded-lg">
|
||||
<div class="text-indigo-600 mb-2">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-8 w-8" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z" />
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="font-bold text-lg mb-2">Easy Integration</h3>
|
||||
<p class="text-gray-600">Simple API to create notifications from anywhere in your Laravel application.</p>
|
||||
</div>
|
||||
|
||||
<div class="bg-emerald-50 p-6 rounded-lg">
|
||||
<div class="text-emerald-600 mb-2">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-8 w-8" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 21a4 4 0 01-4-4V5a2 2 0 012-2h4a2 2 0 012 2v12a4 4 0 01-4 4zm0 0h12a2 2 0 002-2v-4a2 2 0 00-2-2h-2.343M11 7.343l1.657-1.657a2 2 0 012.828 0l2.829 2.829a2 2 0 010 2.828l-8.486 8.485M7 17h.01" />
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="font-bold text-lg mb-2">Multiple Themes</h3>
|
||||
<p class="text-gray-600">Choose from 15+ beautiful themes or create your own custom themes.</p>
|
||||
</div>
|
||||
|
||||
<div class="bg-amber-50 p-6 rounded-lg">
|
||||
<div class="text-amber-600 mb-2">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-8 w-8" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 5a1 1 0 011-1h14a1 1 0 011 1v2a1 1 0 01-1 1H5a1 1 0 01-1-1V5zM4 13a1 1 0 011-1h6a1 1 0 011 1v6a1 1 0 01-1 1H5a1 1 0 01-1-1v-6zM16 13a1 1 0 011-1h2a1 1 0 011 1v6a1 1 0 01-1 1h-2a1 1 0 01-1-1v-6z" />
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="font-bold text-lg mb-2">Flexible Positioning</h3>
|
||||
<p class="text-gray-600">Display notifications at any corner or side of your screen.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-10">
|
||||
<h3 class="text-lg font-medium text-gray-900">Try It Now</h3>
|
||||
<div class="mt-4 flex flex-wrap gap-2">
|
||||
<a href="{{ route('all.types') }}" class="btn-primary">
|
||||
Show All Notification Types
|
||||
</a>
|
||||
<a href="{{ route('themes') }}" class="btn-outline">
|
||||
Explore Themes
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-10">
|
||||
<h3 class="text-lg font-medium text-gray-900">Code Example</h3>
|
||||
<div class="mt-4 code-block">
|
||||
<div class="code-header">
|
||||
<span>Basic Usage</span>
|
||||
</div>
|
||||
<pre><code class="language-php">// Display a success notification
|
||||
flash()->success('Item created successfully!');
|
||||
|
||||
// Display an error notification
|
||||
flash()->error('An error occurred!');
|
||||
|
||||
// Display a warning notification
|
||||
flash()->warning('Warning: This action cannot be undone.');
|
||||
|
||||
// Display an info notification
|
||||
flash()->info('The task is running in the background.');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,349 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Real-World Examples')
|
||||
|
||||
@section('content')
|
||||
<div class="mb-8">
|
||||
<h1 class="section-title">Real-World Examples</h1>
|
||||
<p class="section-subtitle">See how PHPFlasher handles common application scenarios. Click to run each example.</p>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||
{{-- User Registration --}}
|
||||
<div class="card">
|
||||
<div class="h-2 bg-gradient-to-r from-emerald-500 to-green-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center space-x-3 mb-4">
|
||||
<div class="p-3 bg-emerald-100 rounded-xl">
|
||||
<svg class="w-6 h-6 text-emerald-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M18 9v3m0 0v3m0-3h3m-3 0h-3m-2-5a4 4 0 11-8 0 4 4 0 018 0zM3 20a6 6 0 0112 0v1H3v-1z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-lg font-bold text-gray-800">User Registration</h3>
|
||||
<p class="text-sm text-gray-500">Account creation flow</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 mb-4">Simulates a successful user registration with welcome message and email verification notice.</p>
|
||||
|
||||
<button onclick="runExample('registration')" class="btn btn-success w-full mb-4">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"></path>
|
||||
</svg>
|
||||
Run Example
|
||||
</button>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header"><span>PHP</span></div>
|
||||
<pre class="!m-0"><code class="language-php">flash()->success('Welcome! Your account has been created.');
|
||||
flash()->info('Please check your email to verify your account.');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Login Flow --}}
|
||||
<div class="card">
|
||||
<div class="h-2 bg-gradient-to-r from-rose-500 to-red-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center space-x-3 mb-4">
|
||||
<div class="p-3 bg-rose-100 rounded-xl">
|
||||
<svg class="w-6 h-6 text-rose-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-lg font-bold text-gray-800">Login Failed</h3>
|
||||
<p class="text-sm text-gray-500">Authentication error</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 mb-4">Shows how to display login failure messages with helpful guidance.</p>
|
||||
|
||||
<button onclick="runExample('login_failed')" class="btn btn-danger w-full mb-4">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"></path>
|
||||
</svg>
|
||||
Run Example
|
||||
</button>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header"><span>PHP</span></div>
|
||||
<pre class="!m-0"><code class="language-php">flash()->error('Invalid email or password.');
|
||||
flash()->info('Forgot your password? Click here to reset.');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Form Validation --}}
|
||||
<div class="card">
|
||||
<div class="h-2 bg-gradient-to-r from-amber-500 to-yellow-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center space-x-3 mb-4">
|
||||
<div class="p-3 bg-amber-100 rounded-xl">
|
||||
<svg class="w-6 h-6 text-amber-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-lg font-bold text-gray-800">Form Validation</h3>
|
||||
<p class="text-sm text-gray-500">Multiple field errors</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 mb-4">Demonstrates displaying multiple validation errors from a form submission.</p>
|
||||
|
||||
<button onclick="runExample('validation')" class="btn btn-warning w-full mb-4">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"></path>
|
||||
</svg>
|
||||
Run Example
|
||||
</button>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header"><span>PHP</span></div>
|
||||
<pre class="!m-0"><code class="language-php">flash()->error('The email field is required.');
|
||||
flash()->error('Password must be at least 8 characters.');
|
||||
flash()->error('Please accept the terms and conditions.');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Shopping Cart --}}
|
||||
<div class="card">
|
||||
<div class="h-2 bg-gradient-to-r from-indigo-500 to-purple-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center space-x-3 mb-4">
|
||||
<div class="p-3 bg-indigo-100 rounded-xl">
|
||||
<svg class="w-6 h-6 text-indigo-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 3h2l.4 2M7 13h10l4-8H5.4M7 13L5.4 5M7 13l-2.293 2.293c-.63.63-.184 1.707.707 1.707H17m0 0a2 2 0 100 4 2 2 0 000-4zm-8 2a2 2 0 11-4 0 2 2 0 014 0z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-lg font-bold text-gray-800">Shopping Cart</h3>
|
||||
<p class="text-sm text-gray-500">E-commerce interactions</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 mb-4">Shows notifications for adding items to cart with stock warnings and promotions.</p>
|
||||
|
||||
<button onclick="runExample('shopping_cart')" class="btn btn-primary w-full mb-4">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"></path>
|
||||
</svg>
|
||||
Run Example
|
||||
</button>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header"><span>PHP</span></div>
|
||||
<pre class="!m-0"><code class="language-php">flash()->success('iPhone 15 Pro added to cart!');
|
||||
flash()->warning('Only 2 items left in stock!');
|
||||
flash()->info('Add $20 more for free shipping!');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- File Upload --}}
|
||||
<div class="card">
|
||||
<div class="h-2 bg-gradient-to-r from-sky-500 to-cyan-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center space-x-3 mb-4">
|
||||
<div class="p-3 bg-sky-100 rounded-xl">
|
||||
<svg class="w-6 h-6 text-sky-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-lg font-bold text-gray-800">File Upload</h3>
|
||||
<p class="text-sm text-gray-500">Upload progress and status</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 mb-4">Demonstrates file upload progress with success and additional info.</p>
|
||||
|
||||
<button onclick="runExample('file_upload')" class="btn btn-info w-full mb-4">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"></path>
|
||||
</svg>
|
||||
Run Example
|
||||
</button>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header"><span>PHP</span></div>
|
||||
<pre class="!m-0"><code class="language-php">flash()->success('document.pdf uploaded successfully!');
|
||||
flash()->info('File size: 2.4 MB');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Settings Saved --}}
|
||||
<div class="card">
|
||||
<div class="h-2 bg-gradient-to-r from-teal-500 to-green-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center space-x-3 mb-4">
|
||||
<div class="p-3 bg-teal-100 rounded-xl">
|
||||
<svg class="w-6 h-6 text-teal-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"></path>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-lg font-bold text-gray-800">Settings Saved</h3>
|
||||
<p class="text-sm text-gray-500">Preferences updated</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 mb-4">Shows settings save confirmation with additional context.</p>
|
||||
|
||||
<button onclick="runExample('settings')" class="btn btn-success w-full mb-4">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"></path>
|
||||
</svg>
|
||||
Run Example
|
||||
</button>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header"><span>PHP</span></div>
|
||||
<pre class="!m-0"><code class="language-php">flash()->success('Settings saved successfully!');
|
||||
flash()->info('Some changes may require a page refresh.');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Payment Success --}}
|
||||
<div class="card">
|
||||
<div class="h-2 bg-gradient-to-r from-green-500 to-emerald-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center space-x-3 mb-4">
|
||||
<div class="p-3 bg-green-100 rounded-xl">
|
||||
<svg class="w-6 h-6 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-lg font-bold text-gray-800">Payment Success</h3>
|
||||
<p class="text-sm text-gray-500">Transaction completed</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 mb-4">Payment confirmation with order details and receipt notification.</p>
|
||||
|
||||
<button onclick="runExample('payment_success')" class="btn btn-success w-full mb-4">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"></path>
|
||||
</svg>
|
||||
Run Example
|
||||
</button>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header"><span>PHP</span></div>
|
||||
<pre class="!m-0"><code class="language-php">flash()->success('Payment of $149.99 confirmed!');
|
||||
flash()->info('Order #12345 - Receipt sent to your email.');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Payment Failed --}}
|
||||
<div class="card">
|
||||
<div class="h-2 bg-gradient-to-r from-red-500 to-rose-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center space-x-3 mb-4">
|
||||
<div class="p-3 bg-red-100 rounded-xl">
|
||||
<svg class="w-6 h-6 text-red-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-lg font-bold text-gray-800">Payment Failed</h3>
|
||||
<p class="text-sm text-gray-500">Transaction declined</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 mb-4">Payment failure with helpful guidance for resolving the issue.</p>
|
||||
|
||||
<button onclick="runExample('payment_failed')" class="btn btn-danger w-full mb-4">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"></path>
|
||||
</svg>
|
||||
Run Example
|
||||
</button>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header"><span>PHP</span></div>
|
||||
<pre class="!m-0"><code class="language-php">flash()->error('Payment declined by your bank.');
|
||||
flash()->warning('Please try a different payment method.');
|
||||
flash()->info('Your cart has been saved.');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Delete Confirmation --}}
|
||||
<div class="card">
|
||||
<div class="h-2 bg-gradient-to-r from-pink-500 to-rose-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center space-x-3 mb-4">
|
||||
<div class="p-3 bg-pink-100 rounded-xl">
|
||||
<svg class="w-6 h-6 text-pink-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-lg font-bold text-gray-800">Delete Confirmation</h3>
|
||||
<p class="text-sm text-gray-500">SweetAlert dialog</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 mb-4">Uses SweetAlert for a confirmation dialog before deleting.</p>
|
||||
|
||||
<button onclick="runExample('delete_confirm')" class="btn btn-danger w-full mb-4">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"></path>
|
||||
</svg>
|
||||
Run Example
|
||||
</button>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header"><span>PHP</span></div>
|
||||
<pre class="!m-0"><code class="language-php">sweetalert()
|
||||
->showCancelButton()
|
||||
->confirmButtonText('Yes, delete it!')
|
||||
->cancelButtonText('Cancel')
|
||||
->warning('Are you sure? This cannot be undone.');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Session Expiring --}}
|
||||
<div class="card">
|
||||
<div class="h-2 bg-gradient-to-r from-orange-500 to-amber-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center space-x-3 mb-4">
|
||||
<div class="p-3 bg-orange-100 rounded-xl">
|
||||
<svg class="w-6 h-6 text-orange-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-lg font-bold text-gray-800">Session Expiring</h3>
|
||||
<p class="text-sm text-gray-500">Timeout warning</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 mb-4">Alerts user when their session is about to expire.</p>
|
||||
|
||||
<button onclick="runExample('session_expiring')" class="btn btn-warning w-full mb-4">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"></path>
|
||||
</svg>
|
||||
Run Example
|
||||
</button>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header"><span>PHP</span></div>
|
||||
<pre class="!m-0"><code class="language-php">flash()->warning('Your session will expire in 5 minutes.');
|
||||
flash()->info('Click anywhere to stay logged in.');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,67 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Form Example - PHPFlasher Laravel Demo')
|
||||
|
||||
@section('content')
|
||||
<div class="max-w-4xl mx-auto">
|
||||
<div class="bg-white rounded-xl shadow-md overflow-hidden">
|
||||
<div class="p-8">
|
||||
<h2 class="text-2xl font-bold text-gray-900 mb-6">Contact Form Example</h2>
|
||||
|
||||
<div class="mb-8">
|
||||
<p class="text-gray-600">
|
||||
This example demonstrates how PHPFlasher can be used to display form validation errors and success messages.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="code-block mb-8">
|
||||
<div class="code-header">
|
||||
<span>Controller Code</span>
|
||||
</div>
|
||||
<pre><code class="language-php">public function processForm(Request $request)
|
||||
{
|
||||
$validator = Validator::make($request->all(), [
|
||||
'name' => 'required|min:2|max:50',
|
||||
'email' => 'required|email',
|
||||
'subject' => 'required|min:5',
|
||||
'message' => 'required|min:10',
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
flash()->error('Please fix the errors in the form!');
|
||||
return redirect()->back()
|
||||
->withErrors($validator)
|
||||
->withInput();
|
||||
}
|
||||
|
||||
// Success scenario
|
||||
flash()
|
||||
->success('Your message has been sent successfully!')
|
||||
->option('timeout', 8000);
|
||||
|
||||
return redirect()->route('form.example');
|
||||
}</code></pre>
|
||||
</div>
|
||||
|
||||
<form action="{{ route('form.process') }}" method="POST" class="space-y-6">
|
||||
@csrf
|
||||
|
||||
<div>
|
||||
<label for="name" class="block text-sm font-medium text-gray-700">Name</label>
|
||||
<input type="text" name="name" id="name" value="{{ old('name') }}" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500">
|
||||
@error('name')
|
||||
<p class="mt-1 text-sm text-red-600">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="email" class="block text-sm font-medium text-gray-700">Email</label>
|
||||
<input type="email" name="email" id="email" value="{{ old('email') }}" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500">
|
||||
@error('email')
|
||||
<p class="mt-1 text-sm text-red-600">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="subject" class="block text-sm font-medium text-gray-700">Subject</label>
|
||||
<input type="text" name="subject" id="subject" value="{{ old('subject
|
||||
@@ -0,0 +1,197 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Home')
|
||||
|
||||
@section('content')
|
||||
{{-- Hero Section --}}
|
||||
<div class="text-center mb-12">
|
||||
<h1 class="text-4xl md:text-5xl font-bold text-gray-900 mb-4">
|
||||
Beautiful Flash Notifications
|
||||
</h1>
|
||||
<p class="text-xl text-gray-600 max-w-2xl mx-auto mb-8">
|
||||
PHPFlasher makes it easy to add elegant notifications to your Laravel application.
|
||||
Try the quick demos below!
|
||||
</p>
|
||||
|
||||
{{-- Quick Demo Buttons --}}
|
||||
<div class="flex flex-wrap justify-center gap-3 mb-8">
|
||||
<button onclick="showNotification({type: 'success', message: 'Operation completed successfully!', title: 'Success'})"
|
||||
class="btn btn-success">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
|
||||
</svg>
|
||||
Success
|
||||
</button>
|
||||
<button onclick="showNotification({type: 'error', message: 'Something went wrong. Please try again.', title: 'Error'})"
|
||||
class="btn btn-danger">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
|
||||
</svg>
|
||||
Error
|
||||
</button>
|
||||
<button onclick="showNotification({type: 'warning', message: 'Please review your input before continuing.', title: 'Warning'})"
|
||||
class="btn btn-warning">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"></path>
|
||||
</svg>
|
||||
Warning
|
||||
</button>
|
||||
<button onclick="showNotification({type: 'info', message: 'Here is some useful information for you.', title: 'Info'})"
|
||||
class="btn btn-info">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
Info
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Features Grid --}}
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 mb-12">
|
||||
{{-- Feature 1: Types --}}
|
||||
<a href="{{ route('types') }}" class="card group">
|
||||
<div class="h-2 bg-gradient-to-r from-emerald-500 to-teal-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center space-x-3 mb-3">
|
||||
<div class="p-2 bg-emerald-100 rounded-lg group-hover:bg-emerald-200 transition-colors">
|
||||
<svg class="w-6 h-6 text-emerald-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 8h10M7 12h4m1 8l-4-4H5a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v8a2 2 0 01-2 2h-3l-4 4z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="text-xl font-bold text-gray-800">Notification Types</h3>
|
||||
</div>
|
||||
<p class="text-gray-600">Success, error, warning, and info notifications for every use case.</p>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
{{-- Feature 2: Themes --}}
|
||||
<a href="{{ route('themes') }}" class="card group">
|
||||
<div class="h-2 bg-gradient-to-r from-purple-500 to-pink-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center space-x-3 mb-3">
|
||||
<div class="p-2 bg-purple-100 rounded-lg group-hover:bg-purple-200 transition-colors">
|
||||
<svg class="w-6 h-6 text-purple-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 21a4 4 0 01-4-4V5a2 2 0 012-2h4a2 2 0 012 2v12a4 4 0 01-4 4zm0 0h12a2 2 0 002-2v-4a2 2 0 00-2-2h-2.343M11 7.343l1.657-1.657a2 2 0 012.828 0l2.829 2.829a2 2 0 010 2.828l-8.486 8.485M7 17h.01"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="text-xl font-bold text-gray-800">17+ Themes</h3>
|
||||
</div>
|
||||
<p class="text-gray-600">Material, iOS, Slack, Amazon, and many more beautiful themes.</p>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
{{-- Feature 3: Adapters --}}
|
||||
<a href="{{ route('adapters') }}" class="card group">
|
||||
<div class="h-2 bg-gradient-to-r from-blue-500 to-cyan-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center space-x-3 mb-3">
|
||||
<div class="p-2 bg-blue-100 rounded-lg group-hover:bg-blue-200 transition-colors">
|
||||
<svg class="w-6 h-6 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 14v6m-3-3h6M6 10h2a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v2a2 2 0 002 2zm10 0h2a2 2 0 002-2V6a2 2 0 00-2-2h-2a2 2 0 00-2 2v2a2 2 0 002 2zM6 20h2a2 2 0 002-2v-2a2 2 0 00-2-2H6a2 2 0 00-2 2v2a2 2 0 002 2z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="text-xl font-bold text-gray-800">Multiple Adapters</h3>
|
||||
</div>
|
||||
<p class="text-gray-600">Toastr, SweetAlert, Noty, and Notyf adapters included.</p>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
{{-- Feature 4: Positions --}}
|
||||
<a href="{{ route('positions') }}" class="card group">
|
||||
<div class="h-2 bg-gradient-to-r from-amber-500 to-orange-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center space-x-3 mb-3">
|
||||
<div class="p-2 bg-amber-100 rounded-lg group-hover:bg-amber-200 transition-colors">
|
||||
<svg class="w-6 h-6 text-amber-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 5a1 1 0 011-1h14a1 1 0 011 1v2a1 1 0 01-1 1H5a1 1 0 01-1-1V5zM4 13a1 1 0 011-1h6a1 1 0 011 1v6a1 1 0 01-1 1H5a1 1 0 01-1-1v-6zM16 13a1 1 0 011-1h2a1 1 0 011 1v6a1 1 0 01-1 1h-2a1 1 0 01-1-1v-6z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="text-xl font-bold text-gray-800">Flexible Positions</h3>
|
||||
</div>
|
||||
<p class="text-gray-600">Place notifications anywhere on the screen.</p>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
{{-- Feature 5: Examples --}}
|
||||
<a href="{{ route('examples') }}" class="card group">
|
||||
<div class="h-2 bg-gradient-to-r from-rose-500 to-red-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center space-x-3 mb-3">
|
||||
<div class="p-2 bg-rose-100 rounded-lg group-hover:bg-rose-200 transition-colors">
|
||||
<svg class="w-6 h-6 text-rose-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="text-xl font-bold text-gray-800">Real Examples</h3>
|
||||
</div>
|
||||
<p class="text-gray-600">User registration, shopping cart, payments, and more.</p>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
{{-- Feature 6: Playground --}}
|
||||
<a href="{{ route('playground') }}" class="card group">
|
||||
<div class="h-2 bg-gradient-to-r from-indigo-500 to-violet-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center space-x-3 mb-3">
|
||||
<div class="p-2 bg-indigo-100 rounded-lg group-hover:bg-indigo-200 transition-colors">
|
||||
<svg class="w-6 h-6 text-indigo-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"></path>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="text-xl font-bold text-gray-800">Interactive Playground</h3>
|
||||
</div>
|
||||
<p class="text-gray-600">Build and customize notifications in real-time.</p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{{-- Quick Start Code --}}
|
||||
<div class="card mb-12">
|
||||
<div class="card-header">
|
||||
<h2 class="text-xl font-bold text-gray-800">Quick Start</h2>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p class="text-gray-600 mb-4">Get started with PHPFlasher in seconds. Just install and use!</p>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>Installation</span>
|
||||
</div>
|
||||
<pre class="!m-0"><code class="language-bash">composer require php-flasher/flasher-laravel</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>Usage</span>
|
||||
</div>
|
||||
<pre class="!m-0"><code class="language-php">// In your controller
|
||||
flash()->success('Profile updated successfully!');
|
||||
|
||||
// With options
|
||||
flash()->success('Welcome back!', [
|
||||
'position' => 'top-right',
|
||||
'timeout' => 5000,
|
||||
]);
|
||||
|
||||
// Using themes
|
||||
flash()->use('theme.material')->info('New feature available!');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- CTA Section --}}
|
||||
<div class="bg-gradient-to-r from-indigo-600 to-purple-600 rounded-2xl p-8 text-center text-white">
|
||||
<h2 class="text-2xl md:text-3xl font-bold mb-4">Ready to try PHPFlasher?</h2>
|
||||
<p class="text-indigo-100 mb-6 max-w-xl mx-auto">
|
||||
Explore the interactive playground to customize notifications and see the generated code.
|
||||
</p>
|
||||
<a href="{{ route('playground') }}" class="inline-flex items-center px-6 py-3 bg-white text-indigo-600 font-semibold rounded-lg hover:bg-indigo-50 transition-colors">
|
||||
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"></path>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
Open Playground
|
||||
</a>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,297 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||
<title>@yield('title', 'PHPFlasher Demo') - Laravel</title>
|
||||
|
||||
{{-- Tailwind CSS v4 CDN --}}
|
||||
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
|
||||
|
||||
{{-- Prism.js for syntax highlighting --}}
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-tomorrow.min.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/toolbar/prism-toolbar.min.css">
|
||||
|
||||
{{-- Prism.js code block fixes --}}
|
||||
<style>
|
||||
.code-block pre {
|
||||
margin: 0 !important;
|
||||
border-radius: 0 !important;
|
||||
background: #2d2d2d !important;
|
||||
padding: 1rem !important;
|
||||
overflow-x: auto;
|
||||
}
|
||||
.code-block code[class*="language-"] {
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.6;
|
||||
background: transparent !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
{{-- Custom Tailwind components --}}
|
||||
<style type="text/tailwindcss">
|
||||
@layer components {
|
||||
.btn {
|
||||
@apply px-4 py-2 rounded-lg font-medium transition-all duration-200 focus:outline-none focus:ring-2 inline-flex items-center justify-center gap-2 cursor-pointer;
|
||||
}
|
||||
.btn-primary {
|
||||
@apply bg-indigo-600 text-white hover:bg-indigo-700 focus:ring-indigo-500/50;
|
||||
}
|
||||
.btn-success {
|
||||
@apply bg-emerald-600 text-white hover:bg-emerald-700 focus:ring-emerald-500/50;
|
||||
}
|
||||
.btn-danger {
|
||||
@apply bg-rose-600 text-white hover:bg-rose-700 focus:ring-rose-500/50;
|
||||
}
|
||||
.btn-warning {
|
||||
@apply bg-amber-500 text-white hover:bg-amber-600 focus:ring-amber-400/50;
|
||||
}
|
||||
.btn-info {
|
||||
@apply bg-sky-500 text-white hover:bg-sky-600 focus:ring-sky-400/50;
|
||||
}
|
||||
.btn-outline {
|
||||
@apply border border-gray-300 text-gray-700 bg-white hover:bg-gray-50 focus:ring-indigo-500/50;
|
||||
}
|
||||
.btn-sm {
|
||||
@apply px-3 py-1.5 text-sm;
|
||||
}
|
||||
.card {
|
||||
@apply bg-white rounded-xl shadow-md overflow-hidden hover:shadow-lg transition-shadow duration-300;
|
||||
}
|
||||
.card-header {
|
||||
@apply px-6 py-4 border-b border-gray-100;
|
||||
}
|
||||
.card-body {
|
||||
@apply p-6;
|
||||
}
|
||||
.code-block {
|
||||
@apply rounded-lg overflow-hidden shadow-lg my-4;
|
||||
}
|
||||
.code-header {
|
||||
@apply bg-gray-800 text-gray-300 px-4 py-2 flex justify-between items-center text-sm font-mono;
|
||||
}
|
||||
.section-title {
|
||||
@apply text-2xl font-bold text-gray-800 mb-2;
|
||||
}
|
||||
.section-subtitle {
|
||||
@apply text-gray-600 mb-6;
|
||||
}
|
||||
.nav-link {
|
||||
@apply px-3 py-2 rounded-lg text-gray-600 hover:text-indigo-600 hover:bg-indigo-50 transition-colors font-medium;
|
||||
}
|
||||
.nav-link-active {
|
||||
@apply text-indigo-600 bg-indigo-50;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@stack('styles')
|
||||
|
||||
{{-- Preload theme CSS for playground --}}
|
||||
<link rel="stylesheet" href="/vendor/flasher/flasher.min.css">
|
||||
<link rel="stylesheet" href="/vendor/flasher/themes/flasher/flasher.min.css">
|
||||
<link rel="stylesheet" href="/vendor/flasher/themes/material/material.min.css">
|
||||
<link rel="stylesheet" href="/vendor/flasher/themes/ios/ios.min.css">
|
||||
<link rel="stylesheet" href="/vendor/flasher/themes/slack/slack.min.css">
|
||||
<link rel="stylesheet" href="/vendor/flasher/themes/amazon/amazon.min.css">
|
||||
<link rel="stylesheet" href="/vendor/flasher/themes/google/google.min.css">
|
||||
|
||||
{{-- Load main flasher script first, then themes --}}
|
||||
<script src="/vendor/flasher/flasher.min.js"></script>
|
||||
<script src="/vendor/flasher/themes/flasher/flasher.min.js"></script>
|
||||
<script src="/vendor/flasher/themes/material/material.min.js"></script>
|
||||
<script src="/vendor/flasher/themes/ios/ios.min.js"></script>
|
||||
<script src="/vendor/flasher/themes/slack/slack.min.js"></script>
|
||||
<script src="/vendor/flasher/themes/amazon/amazon.min.js"></script>
|
||||
<script src="/vendor/flasher/themes/google/google.min.js"></script>
|
||||
|
||||
{{-- Render server-side notifications --}}
|
||||
@flasher_render
|
||||
</head>
|
||||
<body class="bg-gray-50 antialiased text-gray-900 min-h-screen flex flex-col">
|
||||
{{-- Header --}}
|
||||
<header class="bg-white border-b border-gray-200 sticky top-0 z-50">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex justify-between items-center h-16">
|
||||
{{-- Logo --}}
|
||||
<a href="{{ route('home') }}" class="flex items-center space-x-2">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-8 w-8 text-indigo-600" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M13 10V3L4 14h7v7l9-11h-7z" />
|
||||
</svg>
|
||||
<span class="text-xl font-bold text-gray-900">PHPFlasher</span>
|
||||
<span class="hidden sm:inline-block px-2 py-0.5 text-xs font-medium bg-red-100 text-red-600 rounded-full">Laravel</span>
|
||||
</a>
|
||||
|
||||
{{-- Desktop Navigation --}}
|
||||
<nav class="hidden md:flex items-center space-x-1">
|
||||
<a href="{{ route('home') }}" class="nav-link @if(request()->routeIs('home')) nav-link-active @endif">Home</a>
|
||||
<a href="{{ route('types') }}" class="nav-link @if(request()->routeIs('types')) nav-link-active @endif">Types</a>
|
||||
<a href="{{ route('themes') }}" class="nav-link @if(request()->routeIs('themes')) nav-link-active @endif">Themes</a>
|
||||
<a href="{{ route('adapters') }}" class="nav-link @if(request()->routeIs('adapters')) nav-link-active @endif">Adapters</a>
|
||||
<a href="{{ route('positions') }}" class="nav-link @if(request()->routeIs('positions')) nav-link-active @endif">Positions</a>
|
||||
<a href="{{ route('examples') }}" class="nav-link @if(request()->routeIs('examples')) nav-link-active @endif">Examples</a>
|
||||
<a href="{{ route('playground') }}" class="nav-link @if(request()->routeIs('playground')) nav-link-active @endif">Playground</a>
|
||||
<a href="{{ route('livewire') }}" class="nav-link @if(request()->routeIs('livewire')) nav-link-active @endif">Livewire</a>
|
||||
</nav>
|
||||
|
||||
{{-- External Links --}}
|
||||
<div class="hidden md:flex items-center space-x-3">
|
||||
<a href="https://github.com/php-flasher/php-flasher" target="_blank" class="text-gray-500 hover:text-gray-700">
|
||||
<svg class="h-5 w-5" fill="currentColor" viewBox="0 0 24 24"><path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/></svg>
|
||||
</a>
|
||||
<a href="https://php-flasher.io" target="_blank" class="btn btn-primary btn-sm">
|
||||
Documentation
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{{-- Mobile menu button --}}
|
||||
<button id="mobile-menu-btn" class="md:hidden p-2 rounded-lg text-gray-500 hover:bg-gray-100">
|
||||
<svg class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Mobile Navigation --}}
|
||||
<div id="mobile-menu" class="hidden md:hidden border-t border-gray-200 bg-white">
|
||||
<div class="px-4 py-3 space-y-1">
|
||||
<a href="{{ route('home') }}" class="block px-3 py-2 rounded-lg @if(request()->routeIs('home')) bg-indigo-50 text-indigo-600 @else text-gray-600 hover:bg-gray-50 @endif">Home</a>
|
||||
<a href="{{ route('types') }}" class="block px-3 py-2 rounded-lg @if(request()->routeIs('types')) bg-indigo-50 text-indigo-600 @else text-gray-600 hover:bg-gray-50 @endif">Types</a>
|
||||
<a href="{{ route('themes') }}" class="block px-3 py-2 rounded-lg @if(request()->routeIs('themes')) bg-indigo-50 text-indigo-600 @else text-gray-600 hover:bg-gray-50 @endif">Themes</a>
|
||||
<a href="{{ route('adapters') }}" class="block px-3 py-2 rounded-lg @if(request()->routeIs('adapters')) bg-indigo-50 text-indigo-600 @else text-gray-600 hover:bg-gray-50 @endif">Adapters</a>
|
||||
<a href="{{ route('positions') }}" class="block px-3 py-2 rounded-lg @if(request()->routeIs('positions')) bg-indigo-50 text-indigo-600 @else text-gray-600 hover:bg-gray-50 @endif">Positions</a>
|
||||
<a href="{{ route('examples') }}" class="block px-3 py-2 rounded-lg @if(request()->routeIs('examples')) bg-indigo-50 text-indigo-600 @else text-gray-600 hover:bg-gray-50 @endif">Examples</a>
|
||||
<a href="{{ route('playground') }}" class="block px-3 py-2 rounded-lg @if(request()->routeIs('playground')) bg-indigo-50 text-indigo-600 @else text-gray-600 hover:bg-gray-50 @endif">Playground</a>
|
||||
<a href="{{ route('livewire') }}" class="block px-3 py-2 rounded-lg @if(request()->routeIs('livewire')) bg-indigo-50 text-indigo-600 @else text-gray-600 hover:bg-gray-50 @endif">Livewire</a>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{{-- Main Content --}}
|
||||
<main class="flex-1">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
||||
@yield('content')
|
||||
</div>
|
||||
</main>
|
||||
|
||||
{{-- Footer --}}
|
||||
<footer class="bg-white border-t border-gray-200 mt-auto">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6">
|
||||
<div class="flex flex-col md:flex-row justify-between items-center space-y-4 md:space-y-0">
|
||||
<div class="flex items-center space-x-2 text-gray-500">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M13 10V3L4 14h7v7l9-11h-7z" />
|
||||
</svg>
|
||||
<span>PHPFlasher Demo</span>
|
||||
</div>
|
||||
<div class="flex items-center space-x-6 text-sm text-gray-500">
|
||||
<a href="https://php-flasher.io" target="_blank" class="hover:text-indigo-600">Documentation</a>
|
||||
<a href="https://github.com/php-flasher/php-flasher" target="_blank" class="hover:text-indigo-600">GitHub</a>
|
||||
<span>Made with ❤️ by <a href="https://github.com/yoeunes" target="_blank" class="hover:text-indigo-600">Younes</a></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
{{-- Scripts --}}
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/prism.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-markup-templating.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-php.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/toolbar/prism-toolbar.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/copy-to-clipboard/prism-copy-to-clipboard.min.js"></script>
|
||||
|
||||
<script>
|
||||
// Mobile menu toggle
|
||||
document.getElementById('mobile-menu-btn')?.addEventListener('click', function() {
|
||||
document.getElementById('mobile-menu')?.classList.toggle('hidden');
|
||||
});
|
||||
|
||||
// CSRF token for AJAX requests
|
||||
window.csrfToken = '{{ csrf_token() }}';
|
||||
|
||||
// Helper function for notifications using PHPFlasher's JavaScript API
|
||||
window.showNotification = function(options) {
|
||||
const type = options.type || 'success';
|
||||
const message = options.message || 'Notification message';
|
||||
const title = options.title || null;
|
||||
const position = options.position || 'top-right';
|
||||
const timeout = options.timeout || 5000;
|
||||
|
||||
// Use the theme if specified
|
||||
let plugin = 'flasher';
|
||||
if (options.theme && options.theme !== 'flasher') {
|
||||
plugin = 'theme.' + options.theme;
|
||||
}
|
||||
|
||||
// Build notification options
|
||||
const notificationOptions = {
|
||||
position: position,
|
||||
timeout: timeout,
|
||||
};
|
||||
|
||||
// Call PHPFlasher's JavaScript API
|
||||
flasher.use(plugin).flash(type, message, title, notificationOptions);
|
||||
};
|
||||
|
||||
// Helper function for running examples using client-side notifications
|
||||
window.runExample = function(scenario) {
|
||||
const examples = {
|
||||
registration: [
|
||||
{ type: 'success', message: 'Welcome! Your account has been created.' },
|
||||
{ type: 'info', message: 'Please check your email to verify your account.' }
|
||||
],
|
||||
login_failed: [
|
||||
{ type: 'error', message: 'Invalid email or password.' },
|
||||
{ type: 'info', message: 'Forgot your password? Click here to reset.' }
|
||||
],
|
||||
validation: [
|
||||
{ type: 'error', message: 'The email field is required.' },
|
||||
{ type: 'error', message: 'Password must be at least 8 characters.' },
|
||||
{ type: 'error', message: 'Please accept the terms and conditions.' }
|
||||
],
|
||||
shopping_cart: [
|
||||
{ type: 'success', message: 'iPhone 15 Pro added to cart!' },
|
||||
{ type: 'warning', message: 'Only 2 items left in stock!' },
|
||||
{ type: 'info', message: 'Add $20 more for free shipping!' }
|
||||
],
|
||||
file_upload: [
|
||||
{ type: 'success', message: 'document.pdf uploaded successfully!' },
|
||||
{ type: 'info', message: 'File size: 2.4 MB' }
|
||||
],
|
||||
settings: [
|
||||
{ type: 'success', message: 'Settings saved successfully!' },
|
||||
{ type: 'info', message: 'Some changes may require a page refresh.' }
|
||||
],
|
||||
payment_success: [
|
||||
{ type: 'success', message: 'Payment of $149.99 confirmed!' },
|
||||
{ type: 'info', message: 'Order #12345 - Receipt sent to your email.' }
|
||||
],
|
||||
payment_failed: [
|
||||
{ type: 'error', message: 'Payment declined by your bank.' },
|
||||
{ type: 'warning', message: 'Please try a different payment method.' },
|
||||
{ type: 'info', message: 'Your cart has been saved.' }
|
||||
],
|
||||
delete_confirm: [
|
||||
{ type: 'warning', message: 'Are you sure? This action cannot be undone.' },
|
||||
{ type: 'info', message: 'Click confirm to delete or cancel to keep the item.' }
|
||||
],
|
||||
session_expiring: [
|
||||
{ type: 'warning', message: 'Your session will expire in 5 minutes.' },
|
||||
{ type: 'info', message: 'Click anywhere to stay logged in.' }
|
||||
]
|
||||
};
|
||||
|
||||
const notifications = examples[scenario] || [{ type: 'info', message: 'Example not found' }];
|
||||
notifications.forEach((notification, index) => {
|
||||
setTimeout(() => {
|
||||
flasher.flash(notification.type, notification.message);
|
||||
}, index * 300);
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
@stack('scripts')
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,220 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Livewire Integration')
|
||||
|
||||
@section('content')
|
||||
<div class="mb-8">
|
||||
<h1 class="section-title">Livewire Integration</h1>
|
||||
<p class="section-subtitle">PHPFlasher works seamlessly with Laravel Livewire. See live examples below.</p>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-8">
|
||||
{{-- Counter Component --}}
|
||||
<div class="card">
|
||||
<div class="h-2 bg-gradient-to-r from-indigo-500 to-purple-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center space-x-3 mb-6">
|
||||
<div class="p-3 bg-indigo-100 rounded-xl">
|
||||
<svg class="w-6 h-6 text-indigo-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-lg font-bold text-gray-800">Counter Component</h3>
|
||||
<p class="text-sm text-gray-500">Simple state management</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@livewire('counter')
|
||||
|
||||
<div class="code-block mt-6">
|
||||
<div class="code-header">
|
||||
<span>app/Livewire/Counter.php</span>
|
||||
</div>
|
||||
<pre class="!m-0"><code class="language-php">class Counter extends Component
|
||||
{
|
||||
public int $count = 0;
|
||||
|
||||
public function increment(): void
|
||||
{
|
||||
$this->count++;
|
||||
flash()->success("Count increased to {$this->count}!");
|
||||
}
|
||||
|
||||
public function decrement(): void
|
||||
{
|
||||
$this->count--;
|
||||
flash()->warning("Count decreased to {$this->count}");
|
||||
}
|
||||
|
||||
public function reset(): void
|
||||
{
|
||||
$this->count = 0;
|
||||
flash()->info('Counter has been reset.');
|
||||
}
|
||||
}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Contact Form Component --}}
|
||||
<div class="card">
|
||||
<div class="h-2 bg-gradient-to-r from-emerald-500 to-teal-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center space-x-3 mb-6">
|
||||
<div class="p-3 bg-emerald-100 rounded-xl">
|
||||
<svg class="w-6 h-6 text-emerald-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-lg font-bold text-gray-800">Contact Form</h3>
|
||||
<p class="text-sm text-gray-500">Form validation example</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@livewire('contact-form')
|
||||
|
||||
<div class="code-block mt-6">
|
||||
<div class="code-header">
|
||||
<span>app/Livewire/ContactForm.php</span>
|
||||
</div>
|
||||
<pre class="!m-0"><code class="language-php">class ContactForm extends Component
|
||||
{
|
||||
public string $name = '';
|
||||
public string $email = '';
|
||||
public string $message = '';
|
||||
|
||||
protected $rules = [
|
||||
'name' => 'required|min:2',
|
||||
'email' => 'required|email',
|
||||
'message' => 'required|min:10',
|
||||
];
|
||||
|
||||
public function submit(): void
|
||||
{
|
||||
$this->validate();
|
||||
|
||||
// Process form...
|
||||
|
||||
flash()->success('Message sent successfully!');
|
||||
flash()->info('We will respond within 24 hours.');
|
||||
|
||||
$this->reset(['name', 'email', 'message']);
|
||||
}
|
||||
}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- SweetAlert Events --}}
|
||||
<div class="card mt-8">
|
||||
<div class="h-2 bg-gradient-to-r from-pink-500 to-rose-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center space-x-3 mb-6">
|
||||
<div class="p-3 bg-pink-100 rounded-xl">
|
||||
<svg class="w-6 h-6 text-pink-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-lg font-bold text-gray-800">SweetAlert Confirmations</h3>
|
||||
<p class="text-sm text-gray-500">Handle dialog responses in Livewire</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@livewire('delete-item')
|
||||
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6 mt-6">
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>Component</span>
|
||||
</div>
|
||||
<pre class="!m-0"><code class="language-php">class DeleteItem extends Component
|
||||
{
|
||||
protected $listeners = [
|
||||
'sweetalert:confirmed' => 'onConfirmed',
|
||||
'sweetalert:denied' => 'onDenied',
|
||||
];
|
||||
|
||||
public function confirmDelete(): void
|
||||
{
|
||||
sweetalert()
|
||||
->showDenyButton()
|
||||
->showCancelButton()
|
||||
->confirmButtonText('Yes, delete!')
|
||||
->denyButtonText('Keep it')
|
||||
->warning('Delete this item?');
|
||||
}
|
||||
|
||||
public function onConfirmed(array $payload): void
|
||||
{
|
||||
// Delete the item...
|
||||
flash()->success('Item deleted!');
|
||||
}
|
||||
|
||||
public function onDenied(array $payload): void
|
||||
{
|
||||
flash()->info('Item was kept.');
|
||||
}
|
||||
}</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>Blade Template</span>
|
||||
</div>
|
||||
<pre class="!m-0"><code class="language-php"><div>
|
||||
<button wire:click="confirmDelete"
|
||||
class="btn btn-danger">
|
||||
Delete Item
|
||||
</button>
|
||||
</div></code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Installation Guide --}}
|
||||
<div class="card mt-8">
|
||||
<div class="card-header">
|
||||
<h2 class="text-xl font-bold text-gray-800">Livewire Setup</h2>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||
<div>
|
||||
<h3 class="font-semibold text-gray-800 mb-3">1. Install PHPFlasher</h3>
|
||||
<div class="code-block">
|
||||
<div class="code-header"><span>Terminal</span></div>
|
||||
<pre class="!m-0"><code class="language-bash">composer require php-flasher/flasher-laravel</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3 class="font-semibold text-gray-800 mb-3">2. Use in Components</h3>
|
||||
<div class="code-block">
|
||||
<div class="code-header"><span>PHP</span></div>
|
||||
<pre class="!m-0"><code class="language-php">public function save()
|
||||
{
|
||||
// Your logic...
|
||||
flash()->success('Saved!');
|
||||
}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-6 p-4 bg-indigo-50 rounded-lg">
|
||||
<div class="flex items-start space-x-3">
|
||||
<svg class="w-6 h-6 text-indigo-600 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
<div>
|
||||
<h4 class="font-semibold text-indigo-800">Automatic Livewire Support</h4>
|
||||
<p class="text-indigo-700 text-sm mt-1">PHPFlasher automatically detects Livewire requests and handles them appropriately. No additional configuration needed!</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,41 @@
|
||||
<form wire:submit="submit" class="space-y-4">
|
||||
<div>
|
||||
<label for="name" class="block text-sm font-medium text-gray-700 mb-1">Name</label>
|
||||
<input type="text" id="name" wire:model="name"
|
||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-emerald-500 focus:border-emerald-500 @error('name') border-rose-500 @enderror"
|
||||
placeholder="Your name">
|
||||
@error('name')
|
||||
<p class="mt-1 text-sm text-rose-500">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="email" class="block text-sm font-medium text-gray-700 mb-1">Email</label>
|
||||
<input type="email" id="email" wire:model="email"
|
||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-emerald-500 focus:border-emerald-500 @error('email') border-rose-500 @enderror"
|
||||
placeholder="your@email.com">
|
||||
@error('email')
|
||||
<p class="mt-1 text-sm text-rose-500">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="message" class="block text-sm font-medium text-gray-700 mb-1">Message</label>
|
||||
<textarea id="message" wire:model="message" rows="3"
|
||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-emerald-500 focus:border-emerald-500 @error('message') border-rose-500 @enderror"
|
||||
placeholder="Your message..."></textarea>
|
||||
@error('message')
|
||||
<p class="mt-1 text-sm text-rose-500">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<button type="submit"
|
||||
class="w-full px-4 py-2 bg-emerald-600 hover:bg-emerald-700 text-white font-medium rounded-lg transition-colors flex items-center justify-center space-x-2">
|
||||
<svg wire:loading wire:target="submit" class="animate-spin h-5 w-5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
||||
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
||||
</svg>
|
||||
<span wire:loading.remove wire:target="submit">Send Message</span>
|
||||
<span wire:loading wire:target="submit">Sending...</span>
|
||||
</button>
|
||||
</form>
|
||||
@@ -1,7 +1,22 @@
|
||||
<div>
|
||||
<h1>{{ $count }}</h1>
|
||||
<div class="flex items-center justify-center space-x-4">
|
||||
<button wire:click="decrement"
|
||||
class="w-12 h-12 bg-rose-500 hover:bg-rose-600 text-white rounded-full flex items-center justify-center text-2xl font-bold transition-colors">
|
||||
-
|
||||
</button>
|
||||
|
||||
<button wire:click="increment">+</button>
|
||||
<div class="w-24 h-24 bg-gradient-to-br from-indigo-500 to-purple-600 rounded-2xl flex items-center justify-center">
|
||||
<span class="text-4xl font-bold text-white">{{ $count }}</span>
|
||||
</div>
|
||||
|
||||
<button wire:click="decrement">-</button>
|
||||
<button wire:click="increment"
|
||||
class="w-12 h-12 bg-emerald-500 hover:bg-emerald-600 text-white rounded-full flex items-center justify-center text-2xl font-bold transition-colors">
|
||||
+
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-center mt-4">
|
||||
<button wire:click="reset"
|
||||
class="px-4 py-2 bg-gray-200 hover:bg-gray-300 text-gray-700 rounded-lg text-sm font-medium transition-colors">
|
||||
Reset
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
<div class="flex flex-col items-center space-y-4">
|
||||
<div class="flex items-center space-x-4">
|
||||
<div class="w-16 h-16 bg-gray-100 rounded-lg flex items-center justify-center">
|
||||
<svg class="w-8 h-8 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h4 class="font-semibold text-gray-800">Important Document.pdf</h4>
|
||||
<p class="text-sm text-gray-500">2.4 MB - Modified today</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button wire:click="confirmDelete"
|
||||
class="px-6 py-2 bg-rose-600 hover:bg-rose-700 text-white font-medium rounded-lg transition-colors flex items-center space-x-2">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"></path>
|
||||
</svg>
|
||||
<span>Delete File</span>
|
||||
</button>
|
||||
</div>
|
||||
@@ -0,0 +1,390 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Playground')
|
||||
|
||||
@section('content')
|
||||
<div class="mb-8">
|
||||
<h1 class="section-title">Interactive Playground</h1>
|
||||
<p class="section-subtitle">Build and customize notifications in real-time. See the generated PHP code instantly.</p>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-8">
|
||||
{{-- Configuration Panel --}}
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h2 class="text-xl font-bold text-gray-800">Configuration</h2>
|
||||
</div>
|
||||
<div class="card-body space-y-6">
|
||||
{{-- Type --}}
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">Notification Type</label>
|
||||
<div class="grid grid-cols-4 gap-2">
|
||||
<button onclick="setType('success')" id="type-success" class="type-btn px-3 py-2 rounded-lg border-2 border-emerald-500 bg-emerald-50 text-emerald-700 font-medium text-sm">
|
||||
Success
|
||||
</button>
|
||||
<button onclick="setType('error')" id="type-error" class="type-btn px-3 py-2 rounded-lg border-2 border-gray-200 bg-white text-gray-600 font-medium text-sm hover:border-rose-500 hover:bg-rose-50 hover:text-rose-700">
|
||||
Error
|
||||
</button>
|
||||
<button onclick="setType('warning')" id="type-warning" class="type-btn px-3 py-2 rounded-lg border-2 border-gray-200 bg-white text-gray-600 font-medium text-sm hover:border-amber-500 hover:bg-amber-50 hover:text-amber-700">
|
||||
Warning
|
||||
</button>
|
||||
<button onclick="setType('info')" id="type-info" class="type-btn px-3 py-2 rounded-lg border-2 border-gray-200 bg-white text-gray-600 font-medium text-sm hover:border-sky-500 hover:bg-sky-50 hover:text-sky-700">
|
||||
Info
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Title --}}
|
||||
<div>
|
||||
<label for="title" class="block text-sm font-medium text-gray-700 mb-2">Title (optional)</label>
|
||||
<input type="text" id="title" placeholder="Enter a title..."
|
||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"
|
||||
oninput="updateCode()">
|
||||
</div>
|
||||
|
||||
{{-- Message --}}
|
||||
<div>
|
||||
<label for="message" class="block text-sm font-medium text-gray-700 mb-2">Message</label>
|
||||
<textarea id="message" rows="2" placeholder="Enter your notification message..."
|
||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"
|
||||
oninput="updateCode()">Operation completed successfully!</textarea>
|
||||
</div>
|
||||
|
||||
{{-- Position --}}
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">Position</label>
|
||||
<select id="position" onchange="updateCode()"
|
||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500">
|
||||
<option value="top-right" selected>Top Right (default)</option>
|
||||
<option value="top-left">Top Left</option>
|
||||
<option value="top-center">Top Center</option>
|
||||
<option value="bottom-right">Bottom Right</option>
|
||||
<option value="bottom-left">Bottom Left</option>
|
||||
<option value="bottom-center">Bottom Center</option>
|
||||
<option value="center">Center</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
{{-- Theme --}}
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">Theme</label>
|
||||
<select id="theme" onchange="updateCode()"
|
||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500">
|
||||
<option value="">Default (Flasher)</option>
|
||||
<option value="flasher">Flasher</option>
|
||||
<option value="material">Material</option>
|
||||
<option value="ios">iOS</option>
|
||||
<option value="slack">Slack</option>
|
||||
<option value="amazon">Amazon</option>
|
||||
<option value="google">Google</option>
|
||||
<option value="facebook">Facebook</option>
|
||||
<option value="minimal">Minimal</option>
|
||||
<option value="neon">Neon</option>
|
||||
<option value="emerald">Emerald</option>
|
||||
<option value="sapphire">Sapphire</option>
|
||||
<option value="ruby">Ruby</option>
|
||||
<option value="amber">Amber</option>
|
||||
<option value="jade">Jade</option>
|
||||
<option value="onyx">Onyx</option>
|
||||
<option value="crystal">Crystal</option>
|
||||
<option value="aurora">Aurora</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
{{-- Adapter --}}
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">Adapter</label>
|
||||
<select id="adapter" onchange="updateCode()"
|
||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500">
|
||||
<option value="flasher" selected>Flasher (default)</option>
|
||||
<option value="toastr">Toastr</option>
|
||||
<option value="sweetalert">SweetAlert</option>
|
||||
<option value="noty">Noty</option>
|
||||
<option value="notyf">Notyf</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
{{-- Timeout --}}
|
||||
<div>
|
||||
<label for="timeout" class="block text-sm font-medium text-gray-700 mb-2">
|
||||
Timeout: <span id="timeout-value">5000</span>ms
|
||||
</label>
|
||||
<input type="range" id="timeout" min="1000" max="10000" step="500" value="5000"
|
||||
class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer"
|
||||
oninput="document.getElementById('timeout-value').textContent = this.value; updateCode()">
|
||||
</div>
|
||||
|
||||
{{-- Show Button --}}
|
||||
<button onclick="showPlaygroundNotification()" class="btn btn-primary w-full">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"></path>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
Show Notification
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Code Preview --}}
|
||||
<div class="space-y-6">
|
||||
<div class="card">
|
||||
<div class="card-header flex justify-between items-center">
|
||||
<h2 class="text-xl font-bold text-gray-800">Generated Code</h2>
|
||||
<button onclick="copyCode()" class="btn btn-sm btn-outline">
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"></path>
|
||||
</svg>
|
||||
Copy
|
||||
</button>
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
<div class="code-block !my-0 !rounded-none">
|
||||
<div class="code-header">
|
||||
<span>PHP</span>
|
||||
</div>
|
||||
<pre class="!m-0"><code class="language-php" id="generated-code">flash()->success('Operation completed successfully!');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Preview Card --}}
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h2 class="text-xl font-bold text-gray-800">Preview</h2>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="bg-gray-100 rounded-lg p-6 min-h-[200px] flex items-center justify-center">
|
||||
<div id="preview-notification" class="max-w-sm w-full">
|
||||
{{-- Preview will be rendered here --}}
|
||||
<div class="bg-emerald-500 text-white p-4 rounded-lg shadow-lg">
|
||||
<div class="flex items-start space-x-3">
|
||||
<svg class="w-6 h-6 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
<div>
|
||||
<p id="preview-title" class="font-semibold hidden"></p>
|
||||
<p id="preview-message" class="text-sm opacity-90">Operation completed successfully!</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-sm text-gray-500 mt-3 text-center">This is a static preview. Click "Show Notification" to see the real notification.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Quick Examples --}}
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h2 class="text-xl font-bold text-gray-800">Quick Examples</h2>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="space-y-2">
|
||||
<button onclick="loadExample('simple')" class="btn btn-outline w-full justify-start">
|
||||
Simple Notification
|
||||
</button>
|
||||
<button onclick="loadExample('with_title')" class="btn btn-outline w-full justify-start">
|
||||
With Title
|
||||
</button>
|
||||
<button onclick="loadExample('material_theme')" class="btn btn-outline w-full justify-start">
|
||||
Material Theme
|
||||
</button>
|
||||
<button onclick="loadExample('toastr_adapter')" class="btn btn-outline w-full justify-start">
|
||||
Toastr Adapter
|
||||
</button>
|
||||
<button onclick="loadExample('bottom_center')" class="btn btn-outline w-full justify-start">
|
||||
Bottom Center Position
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
let currentType = 'success';
|
||||
const typeColors = {
|
||||
success: { border: 'border-emerald-500', bg: 'bg-emerald-50', text: 'text-emerald-700', preview: 'bg-emerald-500' },
|
||||
error: { border: 'border-rose-500', bg: 'bg-rose-50', text: 'text-rose-700', preview: 'bg-rose-500' },
|
||||
warning: { border: 'border-amber-500', bg: 'bg-amber-50', text: 'text-amber-700', preview: 'bg-amber-500' },
|
||||
info: { border: 'border-sky-500', bg: 'bg-sky-50', text: 'text-sky-700', preview: 'bg-sky-500' }
|
||||
};
|
||||
|
||||
function setType(type) {
|
||||
currentType = type;
|
||||
|
||||
// Update button styles
|
||||
document.querySelectorAll('.type-btn').forEach(btn => {
|
||||
btn.className = 'type-btn px-3 py-2 rounded-lg border-2 border-gray-200 bg-white text-gray-600 font-medium text-sm';
|
||||
});
|
||||
|
||||
const activeBtn = document.getElementById(`type-${type}`);
|
||||
const colors = typeColors[type];
|
||||
activeBtn.className = `type-btn px-3 py-2 rounded-lg border-2 ${colors.border} ${colors.bg} ${colors.text} font-medium text-sm`;
|
||||
|
||||
// Update preview
|
||||
updatePreview();
|
||||
updateCode();
|
||||
}
|
||||
|
||||
function updatePreview() {
|
||||
const previewDiv = document.querySelector('#preview-notification > div');
|
||||
const colors = typeColors[currentType];
|
||||
previewDiv.className = `${colors.preview} text-white p-4 rounded-lg shadow-lg`;
|
||||
|
||||
const title = document.getElementById('title').value;
|
||||
const message = document.getElementById('message').value;
|
||||
|
||||
document.getElementById('preview-title').textContent = title;
|
||||
document.getElementById('preview-title').classList.toggle('hidden', !title);
|
||||
document.getElementById('preview-message').textContent = message || 'Your notification message...';
|
||||
}
|
||||
|
||||
function updateCode() {
|
||||
const type = currentType;
|
||||
const title = document.getElementById('title').value;
|
||||
const message = document.getElementById('message').value || 'Your message here';
|
||||
const position = document.getElementById('position').value;
|
||||
const theme = document.getElementById('theme').value;
|
||||
const adapter = document.getElementById('adapter').value;
|
||||
const timeout = document.getElementById('timeout').value;
|
||||
|
||||
let code = '';
|
||||
const hasOptions = position !== 'top-right' || timeout !== '5000';
|
||||
|
||||
// Build the code
|
||||
if (theme) {
|
||||
code = `flash()->use('theme.${theme}')`;
|
||||
} else if (adapter !== 'flasher') {
|
||||
code = `${adapter}()`;
|
||||
} else {
|
||||
code = 'flash()';
|
||||
}
|
||||
|
||||
// Add options if needed
|
||||
if (hasOptions) {
|
||||
const options = [];
|
||||
if (position !== 'top-right') {
|
||||
options.push(`'position' => '${position}'`);
|
||||
}
|
||||
if (timeout !== '5000') {
|
||||
options.push(`'timeout' => ${timeout}`);
|
||||
}
|
||||
|
||||
if (title) {
|
||||
code += `\n ->${type}('${message}', '${title}', [${options.join(', ')}]);`;
|
||||
} else {
|
||||
code += `\n ->${type}('${message}', [${options.join(', ')}]);`;
|
||||
}
|
||||
} else {
|
||||
if (title) {
|
||||
code += `->${type}('${message}', '${title}');`;
|
||||
} else {
|
||||
code += `->${type}('${message}');`;
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById('generated-code').textContent = code;
|
||||
Prism.highlightElement(document.getElementById('generated-code'));
|
||||
|
||||
updatePreview();
|
||||
}
|
||||
|
||||
function showPlaygroundNotification() {
|
||||
const options = {
|
||||
type: currentType,
|
||||
message: document.getElementById('message').value || 'Your message here',
|
||||
title: document.getElementById('title').value || undefined,
|
||||
position: document.getElementById('position').value,
|
||||
theme: document.getElementById('theme').value || undefined,
|
||||
adapter: document.getElementById('adapter').value,
|
||||
timeout: parseInt(document.getElementById('timeout').value)
|
||||
};
|
||||
|
||||
showNotification(options);
|
||||
}
|
||||
|
||||
function copyCode() {
|
||||
const code = document.getElementById('generated-code').textContent;
|
||||
navigator.clipboard.writeText(code).then(() => {
|
||||
// Show success feedback
|
||||
const btn = event.target.closest('button');
|
||||
const originalText = btn.innerHTML;
|
||||
btn.innerHTML = '<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg> Copied!';
|
||||
setTimeout(() => {
|
||||
btn.innerHTML = originalText;
|
||||
}, 2000);
|
||||
});
|
||||
}
|
||||
|
||||
function loadExample(example) {
|
||||
const examples = {
|
||||
simple: {
|
||||
type: 'success',
|
||||
title: '',
|
||||
message: 'Data saved successfully!',
|
||||
position: 'top-right',
|
||||
theme: '',
|
||||
adapter: 'flasher',
|
||||
timeout: 5000
|
||||
},
|
||||
with_title: {
|
||||
type: 'info',
|
||||
title: 'New Update',
|
||||
message: 'Version 2.0 is now available!',
|
||||
position: 'top-right',
|
||||
theme: '',
|
||||
adapter: 'flasher',
|
||||
timeout: 5000
|
||||
},
|
||||
material_theme: {
|
||||
type: 'success',
|
||||
title: '',
|
||||
message: 'Material design notification!',
|
||||
position: 'top-right',
|
||||
theme: 'material',
|
||||
adapter: 'flasher',
|
||||
timeout: 5000
|
||||
},
|
||||
toastr_adapter: {
|
||||
type: 'warning',
|
||||
title: 'Warning',
|
||||
message: 'Please review your changes',
|
||||
position: 'top-right',
|
||||
theme: '',
|
||||
adapter: 'toastr',
|
||||
timeout: 5000
|
||||
},
|
||||
bottom_center: {
|
||||
type: 'error',
|
||||
title: '',
|
||||
message: 'Something went wrong!',
|
||||
position: 'bottom-center',
|
||||
theme: '',
|
||||
adapter: 'flasher',
|
||||
timeout: 5000
|
||||
}
|
||||
};
|
||||
|
||||
const ex = examples[example];
|
||||
if (ex) {
|
||||
setType(ex.type);
|
||||
document.getElementById('title').value = ex.title;
|
||||
document.getElementById('message').value = ex.message;
|
||||
document.getElementById('position').value = ex.position;
|
||||
document.getElementById('theme').value = ex.theme;
|
||||
document.getElementById('adapter').value = ex.adapter;
|
||||
document.getElementById('timeout').value = ex.timeout;
|
||||
document.getElementById('timeout-value').textContent = ex.timeout;
|
||||
updateCode();
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
updateCode();
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
@@ -0,0 +1,211 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Positions')
|
||||
|
||||
@section('content')
|
||||
<div class="mb-8">
|
||||
<h1 class="section-title">Notification Positions</h1>
|
||||
<p class="section-subtitle">Place your notifications anywhere on the screen. Click any position to see it in action.</p>
|
||||
</div>
|
||||
|
||||
{{-- Interactive Position Grid --}}
|
||||
<div class="card mb-8">
|
||||
<div class="card-header">
|
||||
<h2 class="text-xl font-bold text-gray-800">Click a Position</h2>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="bg-gray-100 rounded-xl p-4 relative" style="min-height: 400px;">
|
||||
{{-- Visual Browser Frame --}}
|
||||
<div class="bg-white rounded-lg shadow-lg overflow-hidden h-full" style="min-height: 380px;">
|
||||
{{-- Browser Header --}}
|
||||
<div class="bg-gray-200 px-4 py-2 flex items-center space-x-2">
|
||||
<div class="w-3 h-3 bg-red-400 rounded-full"></div>
|
||||
<div class="w-3 h-3 bg-yellow-400 rounded-full"></div>
|
||||
<div class="w-3 h-3 bg-green-400 rounded-full"></div>
|
||||
<div class="flex-1 ml-4">
|
||||
<div class="bg-white rounded px-3 py-1 text-sm text-gray-500 max-w-md">your-app.com</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Position Grid --}}
|
||||
<div class="grid grid-cols-3 grid-rows-3 gap-2 p-4" style="min-height: 340px;">
|
||||
{{-- Top Left --}}
|
||||
<button onclick="showNotification({type: 'info', message: 'Top Left notification', position: 'top-left'})"
|
||||
class="flex items-start justify-start p-4 bg-indigo-50 hover:bg-indigo-100 rounded-lg transition-colors group">
|
||||
<div class="bg-indigo-500 text-white px-3 py-2 rounded-lg text-sm font-medium group-hover:scale-105 transition-transform">
|
||||
top-left
|
||||
</div>
|
||||
</button>
|
||||
|
||||
{{-- Top Center --}}
|
||||
<button onclick="showNotification({type: 'info', message: 'Top Center notification', position: 'top-center'})"
|
||||
class="flex items-start justify-center p-4 bg-purple-50 hover:bg-purple-100 rounded-lg transition-colors group">
|
||||
<div class="bg-purple-500 text-white px-3 py-2 rounded-lg text-sm font-medium group-hover:scale-105 transition-transform">
|
||||
top-center
|
||||
</div>
|
||||
</button>
|
||||
|
||||
{{-- Top Right --}}
|
||||
<button onclick="showNotification({type: 'info', message: 'Top Right notification', position: 'top-right'})"
|
||||
class="flex items-start justify-end p-4 bg-pink-50 hover:bg-pink-100 rounded-lg transition-colors group">
|
||||
<div class="bg-pink-500 text-white px-3 py-2 rounded-lg text-sm font-medium group-hover:scale-105 transition-transform">
|
||||
top-right
|
||||
</div>
|
||||
</button>
|
||||
|
||||
{{-- Center Left --}}
|
||||
<button onclick="showNotification({type: 'info', message: 'Center Left notification', position: 'center-left'})"
|
||||
class="flex items-center justify-start p-4 bg-sky-50 hover:bg-sky-100 rounded-lg transition-colors group">
|
||||
<div class="bg-sky-500 text-white px-3 py-2 rounded-lg text-sm font-medium group-hover:scale-105 transition-transform">
|
||||
center-left
|
||||
</div>
|
||||
</button>
|
||||
|
||||
{{-- Center --}}
|
||||
<button onclick="showNotification({type: 'info', message: 'Center notification', position: 'center'})"
|
||||
class="flex items-center justify-center p-4 bg-amber-50 hover:bg-amber-100 rounded-lg transition-colors group">
|
||||
<div class="bg-amber-500 text-white px-3 py-2 rounded-lg text-sm font-medium group-hover:scale-105 transition-transform">
|
||||
center
|
||||
</div>
|
||||
</button>
|
||||
|
||||
{{-- Center Right --}}
|
||||
<button onclick="showNotification({type: 'info', message: 'Center Right notification', position: 'center-right'})"
|
||||
class="flex items-center justify-end p-4 bg-emerald-50 hover:bg-emerald-100 rounded-lg transition-colors group">
|
||||
<div class="bg-emerald-500 text-white px-3 py-2 rounded-lg text-sm font-medium group-hover:scale-105 transition-transform">
|
||||
center-right
|
||||
</div>
|
||||
</button>
|
||||
|
||||
{{-- Bottom Left --}}
|
||||
<button onclick="showNotification({type: 'info', message: 'Bottom Left notification', position: 'bottom-left'})"
|
||||
class="flex items-end justify-start p-4 bg-rose-50 hover:bg-rose-100 rounded-lg transition-colors group">
|
||||
<div class="bg-rose-500 text-white px-3 py-2 rounded-lg text-sm font-medium group-hover:scale-105 transition-transform">
|
||||
bottom-left
|
||||
</div>
|
||||
</button>
|
||||
|
||||
{{-- Bottom Center --}}
|
||||
<button onclick="showNotification({type: 'info', message: 'Bottom Center notification', position: 'bottom-center'})"
|
||||
class="flex items-end justify-center p-4 bg-teal-50 hover:bg-teal-100 rounded-lg transition-colors group">
|
||||
<div class="bg-teal-500 text-white px-3 py-2 rounded-lg text-sm font-medium group-hover:scale-105 transition-transform">
|
||||
bottom-center
|
||||
</div>
|
||||
</button>
|
||||
|
||||
{{-- Bottom Right --}}
|
||||
<button onclick="showNotification({type: 'info', message: 'Bottom Right notification', position: 'bottom-right'})"
|
||||
class="flex items-end justify-end p-4 bg-orange-50 hover:bg-orange-100 rounded-lg transition-colors group">
|
||||
<div class="bg-orange-500 text-white px-3 py-2 rounded-lg text-sm font-medium group-hover:scale-105 transition-transform">
|
||||
bottom-right
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Quick Buttons --}}
|
||||
<div class="card mb-8">
|
||||
<div class="card-header">
|
||||
<h2 class="text-xl font-bold text-gray-800">Quick Position Tests</h2>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="flex flex-wrap gap-3">
|
||||
<button onclick="showNotification({type: 'success', message: 'Top Right (Default)', position: 'top-right'})"
|
||||
class="btn btn-success">Top Right</button>
|
||||
<button onclick="showNotification({type: 'error', message: 'Top Left notification', position: 'top-left'})"
|
||||
class="btn btn-danger">Top Left</button>
|
||||
<button onclick="showNotification({type: 'warning', message: 'Bottom Right notification', position: 'bottom-right'})"
|
||||
class="btn btn-warning">Bottom Right</button>
|
||||
<button onclick="showNotification({type: 'info', message: 'Bottom Left notification', position: 'bottom-left'})"
|
||||
class="btn btn-info">Bottom Left</button>
|
||||
<button onclick="showNotification({type: 'success', message: 'Top Center notification', position: 'top-center'})"
|
||||
class="btn btn-outline">Top Center</button>
|
||||
<button onclick="showNotification({type: 'info', message: 'Bottom Center notification', position: 'bottom-center'})"
|
||||
class="btn btn-outline">Bottom Center</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Code Examples --}}
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="text-lg font-bold text-gray-800">Inline Position</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p class="text-gray-600 mb-4">Set the position directly when creating a notification.</p>
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>PHP</span>
|
||||
</div>
|
||||
<pre class="!m-0"><code class="language-php">flash()
|
||||
->option('position', 'top-left')
|
||||
->success('Profile updated!');
|
||||
|
||||
// Or use the fluent method
|
||||
flash()
|
||||
->position('bottom-right')
|
||||
->info('New message received!');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="text-lg font-bold text-gray-800">Global Configuration</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p class="text-gray-600 mb-4">Set a default position for all notifications in your config file.</p>
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>config/flasher.php</span>
|
||||
</div>
|
||||
<pre class="!m-0"><code class="language-php">return [
|
||||
'default' => 'flasher',
|
||||
'options' => [
|
||||
'position' => 'bottom-right',
|
||||
],
|
||||
];</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Position Reference --}}
|
||||
<div class="card mt-6">
|
||||
<div class="card-header">
|
||||
<h2 class="text-xl font-bold text-gray-800">Available Positions</h2>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
<div class="p-4 bg-gray-50 rounded-lg">
|
||||
<h4 class="font-semibold text-gray-800 mb-2">Top Positions</h4>
|
||||
<ul class="space-y-1 text-gray-600 text-sm">
|
||||
<li><code class="bg-gray-200 px-2 py-0.5 rounded">top-left</code></li>
|
||||
<li><code class="bg-gray-200 px-2 py-0.5 rounded">top-center</code></li>
|
||||
<li><code class="bg-gray-200 px-2 py-0.5 rounded">top-right</code> <span class="text-emerald-600">(default)</span></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="p-4 bg-gray-50 rounded-lg">
|
||||
<h4 class="font-semibold text-gray-800 mb-2">Center Positions</h4>
|
||||
<ul class="space-y-1 text-gray-600 text-sm">
|
||||
<li><code class="bg-gray-200 px-2 py-0.5 rounded">center-left</code></li>
|
||||
<li><code class="bg-gray-200 px-2 py-0.5 rounded">center</code></li>
|
||||
<li><code class="bg-gray-200 px-2 py-0.5 rounded">center-right</code></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="p-4 bg-gray-50 rounded-lg">
|
||||
<h4 class="font-semibold text-gray-800 mb-2">Bottom Positions</h4>
|
||||
<ul class="space-y-1 text-gray-600 text-sm">
|
||||
<li><code class="bg-gray-200 px-2 py-0.5 rounded">bottom-left</code></li>
|
||||
<li><code class="bg-gray-200 px-2 py-0.5 rounded">bottom-center</code></li>
|
||||
<li><code class="bg-gray-200 px-2 py-0.5 rounded">bottom-right</code></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,75 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Themes')
|
||||
|
||||
@section('content')
|
||||
<div class="mb-8">
|
||||
<h1 class="section-title">Theme Gallery</h1>
|
||||
<p class="section-subtitle">Choose from 17+ beautiful themes to match your application's design.</p>
|
||||
</div>
|
||||
|
||||
{{-- Theme Grid --}}
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4 mb-12">
|
||||
@php
|
||||
$themes = [
|
||||
['name' => 'flasher', 'label' => 'Flasher', 'desc' => 'Default theme', 'gradient' => 'from-indigo-500 to-indigo-600'],
|
||||
['name' => 'material', 'label' => 'Material', 'desc' => 'Google Material', 'gradient' => 'from-blue-500 to-blue-600'],
|
||||
['name' => 'ios', 'label' => 'iOS', 'desc' => 'Apple style', 'gradient' => 'from-slate-600 to-slate-700'],
|
||||
['name' => 'slack', 'label' => 'Slack', 'desc' => 'Slack messaging', 'gradient' => 'from-purple-500 to-purple-600'],
|
||||
['name' => 'amazon', 'label' => 'Amazon', 'desc' => 'Amazon alerts', 'gradient' => 'from-orange-500 to-orange-600'],
|
||||
['name' => 'google', 'label' => 'Google', 'desc' => 'Google notifications', 'gradient' => 'from-red-500 to-yellow-500'],
|
||||
['name' => 'facebook', 'label' => 'Facebook', 'desc' => 'Facebook style', 'gradient' => 'from-blue-600 to-blue-700'],
|
||||
['name' => 'minimal', 'label' => 'Minimal', 'desc' => 'Ultra clean', 'gradient' => 'from-gray-400 to-gray-500'],
|
||||
['name' => 'neon', 'label' => 'Neon', 'desc' => 'Bright & bold', 'gradient' => 'from-pink-500 to-rose-500'],
|
||||
['name' => 'emerald', 'label' => 'Emerald', 'desc' => 'Green palette', 'gradient' => 'from-emerald-500 to-green-600'],
|
||||
['name' => 'sapphire', 'label' => 'Sapphire', 'desc' => 'Blue elegance', 'gradient' => 'from-blue-500 to-indigo-600'],
|
||||
['name' => 'ruby', 'label' => 'Ruby', 'desc' => 'Red accents', 'gradient' => 'from-red-500 to-rose-600'],
|
||||
['name' => 'amber', 'label' => 'Amber', 'desc' => 'Warm tones', 'gradient' => 'from-amber-400 to-orange-500'],
|
||||
['name' => 'jade', 'label' => 'Jade', 'desc' => 'Soft green', 'gradient' => 'from-teal-500 to-green-600'],
|
||||
['name' => 'onyx', 'label' => 'Onyx', 'desc' => 'Dark mode', 'gradient' => 'from-slate-700 to-slate-900'],
|
||||
['name' => 'crystal', 'label' => 'Crystal', 'desc' => 'Transparent', 'gradient' => 'from-cyan-400 to-blue-500'],
|
||||
['name' => 'aurora', 'label' => 'Aurora', 'desc' => 'Gradient effects', 'gradient' => 'from-green-400 via-blue-500 to-purple-500'],
|
||||
];
|
||||
@endphp
|
||||
|
||||
@foreach($themes as $theme)
|
||||
<div class="card group cursor-pointer" onclick="showNotification({type: 'success', message: 'This is the {{ $theme['label'] }} theme!', title: '{{ $theme['label'] }} Theme', theme: '{{ $theme['name'] }}'})">
|
||||
<div class="h-20 bg-gradient-to-br {{ $theme['gradient'] }} flex items-center justify-center">
|
||||
<span class="text-white text-2xl font-bold">{{ substr($theme['label'], 0, 1) }}</span>
|
||||
</div>
|
||||
<div class="p-4">
|
||||
<h3 class="font-semibold text-gray-800">{{ $theme['label'] }}</h3>
|
||||
<p class="text-sm text-gray-500">{{ $theme['desc'] }}</p>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
{{-- Usage Example --}}
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h2 class="text-xl font-bold text-gray-800">Using Themes</h2>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p class="text-gray-600 mb-4">Apply themes to your notifications with the <code class="bg-gray-100 px-2 py-1 rounded">use()</code> method.</p>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>PHP</span>
|
||||
</div>
|
||||
<pre class="!m-0"><code class="language-php">// Use a specific theme
|
||||
flash()->use('theme.material')->success('Material design notification!');
|
||||
|
||||
// Different themes for different messages
|
||||
flash()->use('theme.ios')->info('iOS style notification');
|
||||
flash()->use('theme.slack')->warning('Slack style warning');
|
||||
flash()->use('theme.amazon')->success('Amazon style success');
|
||||
|
||||
// Set default theme in config/flasher.php
|
||||
return [
|
||||
'default' => 'theme.material',
|
||||
];</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,200 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Notification Types')
|
||||
|
||||
@section('content')
|
||||
<div class="mb-8">
|
||||
<h1 class="section-title">Notification Types</h1>
|
||||
<p class="section-subtitle">PHPFlasher supports four notification types for different scenarios.</p>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-8">
|
||||
{{-- Success --}}
|
||||
<div class="card">
|
||||
<div class="h-2 bg-emerald-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<div class="flex items-center space-x-3">
|
||||
<div class="p-3 bg-emerald-100 rounded-xl">
|
||||
<svg class="w-8 h-8 text-emerald-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="text-2xl font-bold text-gray-800">Success</h2>
|
||||
<p class="text-gray-500">Positive feedback</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 mb-4">Use success notifications for completed actions, confirmations, and positive feedback.</p>
|
||||
|
||||
<div class="space-y-2 mb-6">
|
||||
<button onclick="showNotification({type: 'success', message: 'Your profile has been updated successfully!'})"
|
||||
class="btn btn-success w-full justify-start">
|
||||
Profile Updated
|
||||
</button>
|
||||
<button onclick="showNotification({type: 'success', message: 'Your account has been created. Welcome aboard!', title: 'Account Created'})"
|
||||
class="btn btn-success w-full justify-start">
|
||||
Account Created
|
||||
</button>
|
||||
<button onclick="showNotification({type: 'success', message: 'Payment of $99.00 confirmed. Receipt sent to your email.', title: 'Payment Successful'})"
|
||||
class="btn btn-success w-full justify-start">
|
||||
Payment Confirmed
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>PHP</span>
|
||||
</div>
|
||||
<pre class="!m-0"><code class="language-php">flash()->success('Profile updated successfully!');
|
||||
|
||||
// With title
|
||||
flash()->success('Welcome aboard!', 'Account Created');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Error --}}
|
||||
<div class="card">
|
||||
<div class="h-2 bg-rose-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<div class="flex items-center space-x-3">
|
||||
<div class="p-3 bg-rose-100 rounded-xl">
|
||||
<svg class="w-8 h-8 text-rose-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="text-2xl font-bold text-gray-800">Error</h2>
|
||||
<p class="text-gray-500">Failures and issues</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 mb-4">Use error notifications for validation failures, server errors, and problems.</p>
|
||||
|
||||
<div class="space-y-2 mb-6">
|
||||
<button onclick="showNotification({type: 'error', message: 'Invalid email or password. Please try again.'})"
|
||||
class="btn btn-danger w-full justify-start">
|
||||
Login Failed
|
||||
</button>
|
||||
<button onclick="showNotification({type: 'error', message: 'Your card was declined. Please try another payment method.', title: 'Payment Failed'})"
|
||||
class="btn btn-danger w-full justify-start">
|
||||
Payment Declined
|
||||
</button>
|
||||
<button onclick="showNotification({type: 'error', message: 'Unable to connect to server. Please check your connection.', title: 'Connection Error'})"
|
||||
class="btn btn-danger w-full justify-start">
|
||||
Server Error
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>PHP</span>
|
||||
</div>
|
||||
<pre class="!m-0"><code class="language-php">flash()->error('Invalid credentials.');
|
||||
|
||||
// With title
|
||||
flash()->error('Please try again.', 'Payment Failed');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Warning --}}
|
||||
<div class="card">
|
||||
<div class="h-2 bg-amber-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<div class="flex items-center space-x-3">
|
||||
<div class="p-3 bg-amber-100 rounded-xl">
|
||||
<svg class="w-8 h-8 text-amber-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="text-2xl font-bold text-gray-800">Warning</h2>
|
||||
<p class="text-gray-500">Caution alerts</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 mb-4">Use warning notifications to alert users about potential issues or important notices.</p>
|
||||
|
||||
<div class="space-y-2 mb-6">
|
||||
<button onclick="showNotification({type: 'warning', message: 'Your session will expire in 5 minutes.'})"
|
||||
class="btn btn-warning w-full justify-start">
|
||||
Session Expiring
|
||||
</button>
|
||||
<button onclick="showNotification({type: 'warning', message: 'You have unsaved changes that will be lost.', title: 'Unsaved Changes'})"
|
||||
class="btn btn-warning w-full justify-start">
|
||||
Unsaved Changes
|
||||
</button>
|
||||
<button onclick="showNotification({type: 'warning', message: 'Only 2 items left in stock!', title: 'Low Stock'})"
|
||||
class="btn btn-warning w-full justify-start">
|
||||
Low Stock Alert
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>PHP</span>
|
||||
</div>
|
||||
<pre class="!m-0"><code class="language-php">flash()->warning('Session expiring soon.');
|
||||
|
||||
// With title
|
||||
flash()->warning('Only 2 left!', 'Low Stock');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Info --}}
|
||||
<div class="card">
|
||||
<div class="h-2 bg-sky-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<div class="flex items-center space-x-3">
|
||||
<div class="p-3 bg-sky-100 rounded-xl">
|
||||
<svg class="w-8 h-8 text-sky-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="text-2xl font-bold text-gray-800">Info</h2>
|
||||
<p class="text-gray-500">Neutral information</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 mb-4">Use info notifications for tips, updates, and general information.</p>
|
||||
|
||||
<div class="space-y-2 mb-6">
|
||||
<button onclick="showNotification({type: 'info', message: 'A new version is available. Click here to update.'})"
|
||||
class="btn btn-info w-full justify-start">
|
||||
Update Available
|
||||
</button>
|
||||
<button onclick="showNotification({type: 'info', message: 'Tip: You can use keyboard shortcuts for faster navigation.', title: 'Pro Tip'})"
|
||||
class="btn btn-info w-full justify-start">
|
||||
Helpful Tip
|
||||
</button>
|
||||
<button onclick="showNotification({type: 'info', message: 'Your report is being generated and will be ready shortly.'})"
|
||||
class="btn btn-info w-full justify-start">
|
||||
Processing Status
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>PHP</span>
|
||||
</div>
|
||||
<pre class="!m-0"><code class="language-php">flash()->info('New version available!');
|
||||
|
||||
// With title
|
||||
flash()->info('Use shortcuts!', 'Pro Tip');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
+13
-20
@@ -2,26 +2,19 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use App\Entity\Book;
|
||||
use App\Http\Controllers\DemoController;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
Route::get('/', function () {
|
||||
sweetalert()->timerProgressBar()->success('Your account has been successfully created!');
|
||||
noty()->layout('topCenter')->success('Welcome back, John Doe!');
|
||||
notyf()->ripple(false)->warning('Your subscription is about to expire in 3 days.');
|
||||
toastr()->positionClass('toast-bottom-left')->error('Payment failed. Please try again.');
|
||||
flash()->use('flasher')->success('Your profile has been updated successfully.');
|
||||
flash()->created(new Book('The Great Gatsby'));
|
||||
flash()->saved(new Book('1984'));
|
||||
session()->flash('success', 'Your settings have been saved.');
|
||||
return view('welcome');
|
||||
})->name('app_home');
|
||||
// Main pages
|
||||
Route::get('/', [DemoController::class, 'home'])->name('home');
|
||||
Route::get('/types', [DemoController::class, 'types'])->name('types');
|
||||
Route::get('/themes', [DemoController::class, 'themes'])->name('themes');
|
||||
Route::get('/adapters', [DemoController::class, 'adapters'])->name('adapters');
|
||||
Route::get('/positions', [DemoController::class, 'positions'])->name('positions');
|
||||
Route::get('/examples', [DemoController::class, 'examples'])->name('examples');
|
||||
Route::get('/playground', [DemoController::class, 'playground'])->name('playground');
|
||||
Route::get('/livewire', [DemoController::class, 'livewire'])->name('livewire');
|
||||
|
||||
Route::get('/redirect', function () {
|
||||
session()->flash('success', 'You have been redirected successfully.');
|
||||
return redirect('/destination');
|
||||
});
|
||||
|
||||
Route::get('/destination', function () {
|
||||
return view('welcome');
|
||||
});
|
||||
// AJAX endpoints
|
||||
Route::post('/notify', [DemoController::class, 'notify'])->name('notify');
|
||||
Route::post('/example/{scenario}', [DemoController::class, 'runExample'])->name('example.run');
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
it('stores and retrieves flash notifications with json serialization', function () {
|
||||
// Trigger a flash notification
|
||||
$this->get('/');
|
||||
|
||||
flash()->success('Test notification', ['title' => 'Success']);
|
||||
|
||||
// Make another request to retrieve from session
|
||||
$response = $this->get('/');
|
||||
|
||||
$response->assertStatus(200);
|
||||
});
|
||||
|
||||
it('handles multiple flash notifications across requests', function () {
|
||||
flash()->success('First message');
|
||||
flash()->error('Second message');
|
||||
flash()->warning('Third message');
|
||||
|
||||
$response = $this->get('/');
|
||||
$response->assertStatus(200);
|
||||
});
|
||||
|
||||
it('preserves notification properties through json session roundtrip', function () {
|
||||
flash()
|
||||
->options(['position' => 'top-right', 'timeout' => 5000])
|
||||
->success('Test message');
|
||||
|
||||
$response = $this->get('/');
|
||||
$response->assertStatus(200);
|
||||
});
|
||||
|
||||
it('works with different notification types', function () {
|
||||
flash()->success('Success message');
|
||||
flash()->error('Error message');
|
||||
flash()->warning('Warning message');
|
||||
flash()->info('Info message');
|
||||
|
||||
$response = $this->get('/');
|
||||
$response->assertStatus(200);
|
||||
});
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"success": false,
|
||||
"errors": "npm warn exec The following package was not found and will be installed: vite@7.3.1\nfailed to load config from /Users/yoeunes/projects/flasher/php-flasher/demo/laravel/vite.config.js\nerror during build:\nError [ERR_MODULE_NOT_FOUND]: Cannot find package 'vite' imported from /Users/yoeunes/projects/flasher/php-flasher/node_modules/.vite-temp/vite.config.js.timestamp-1772405569113-b016e3f78b86a8.mjs\n at Object.getPackageJSONURL (node:internal/modules/package_json_reader:255:9)\n at packageResolve (node:internal/modules/esm/resolve:767:81)\n at moduleResolve (node:internal/modules/esm/resolve:853:18)\n at defaultResolve (node:internal/modules/esm/resolve:983:11)\n at ModuleLoader.defaultResolve (node:internal/modules/esm/loader:799:12)\n at #cachedDefaultResolve (node:internal/modules/esm/loader:723:25)\n at ModuleLoader.resolve (node:internal/modules/esm/loader:706:38)\n at ModuleLoader.getModuleJobForImport (node:internal/modules/esm/loader:307:38)\n at #link (node:internal/modules/esm/module_job:170:49)\n",
|
||||
"timestamp": "2026-03-01 22:52:49",
|
||||
"vite_ruby": "3.9.3",
|
||||
"digest": "f670d25672cb5f6c5badc00b4d6aca0d4d0f25ae"
|
||||
}
|
||||
@@ -5,11 +5,18 @@
|
||||
/.env.*.local
|
||||
/config/secrets/prod/prod.decrypt.private.php
|
||||
/public/bundles/
|
||||
/public/vendor/flasherg
|
||||
/public/vendor/flasher
|
||||
/var/
|
||||
/vendor/
|
||||
###< symfony/framework-bundle ###
|
||||
|
||||
###> symfony/webpack-encore-bundle ###
|
||||
/node_modules/
|
||||
/public/build/
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
###< symfony/webpack-encore-bundle ###
|
||||
|
||||
###> phpstan/phpstan ###
|
||||
phpstan.neon
|
||||
###< phpstan/phpstan ###
|
||||
|
||||
@@ -1 +1 @@
|
||||
8.2
|
||||
8.4
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* PHPFlasher Symfony Demo
|
||||
*
|
||||
* Main JavaScript entry point.
|
||||
* Note: PHPFlasher and other libraries are loaded via CDN in the layout.
|
||||
*/
|
||||
|
||||
// Import styles
|
||||
import './styles/app.css';
|
||||
|
||||
// Custom demo functionality can be added here
|
||||
console.log('PHPFlasher Symfony Demo loaded');
|
||||
@@ -0,0 +1,4 @@
|
||||
/* PHPFlasher Symfony Demo - Custom Styles */
|
||||
|
||||
/* Any custom styles can be added here */
|
||||
/* Note: Main styling is handled via Tailwind CSS v4 CDN in the layout */
|
||||
+92
-21
@@ -6,7 +6,70 @@
|
||||
"repositories": [
|
||||
{
|
||||
"type": "path",
|
||||
"url": "../..",
|
||||
"url": "../../src/Prime",
|
||||
"options": {
|
||||
"symlink": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "path",
|
||||
"url": "../../src/Symfony",
|
||||
"options": {
|
||||
"symlink": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "path",
|
||||
"url": "../../src/Noty/Prime",
|
||||
"options": {
|
||||
"symlink": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "path",
|
||||
"url": "../../src/Noty/Symfony",
|
||||
"options": {
|
||||
"symlink": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "path",
|
||||
"url": "../../src/Notyf/Prime",
|
||||
"options": {
|
||||
"symlink": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "path",
|
||||
"url": "../../src/Notyf/Symfony",
|
||||
"options": {
|
||||
"symlink": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "path",
|
||||
"url": "../../src/SweetAlert/Prime",
|
||||
"options": {
|
||||
"symlink": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "path",
|
||||
"url": "../../src/SweetAlert/Symfony",
|
||||
"options": {
|
||||
"symlink": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "path",
|
||||
"url": "../../src/Toastr/Prime",
|
||||
"options": {
|
||||
"symlink": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "path",
|
||||
"url": "../../src/Toastr/Symfony",
|
||||
"options": {
|
||||
"symlink": true
|
||||
}
|
||||
@@ -16,27 +79,35 @@
|
||||
"php": ">=8.2",
|
||||
"ext-ctype": "*",
|
||||
"ext-iconv": "*",
|
||||
"nelmio/security-bundle": "^3.4.2",
|
||||
"php-flasher/php-flasher": "@dev",
|
||||
"phpstan/phpstan-symfony": "^2.0.2",
|
||||
"symfony/console": "7.2.*",
|
||||
"symfony/dotenv": "7.2.*",
|
||||
"symfony/flex": "^2.4.7",
|
||||
"symfony/framework-bundle": "7.2.*",
|
||||
"symfony/monolog-bundle": "^3.10",
|
||||
"symfony/notifier": "7.2.*",
|
||||
"symfony/runtime": "7.2.*",
|
||||
"symfony/translation": "7.2.*",
|
||||
"symfony/twig-bundle": "7.2.*",
|
||||
"symfony/yaml": "7.2.*",
|
||||
"twig/extra-bundle": "^2.12|^3.20",
|
||||
"twig/twig": "^2.12|^3.20"
|
||||
"nelmio/security-bundle": "^3.4",
|
||||
"php-flasher/flasher": "@dev",
|
||||
"php-flasher/flasher-symfony": "@dev",
|
||||
"php-flasher/flasher-noty": "@dev",
|
||||
"php-flasher/flasher-noty-symfony": "@dev",
|
||||
"php-flasher/flasher-notyf": "@dev",
|
||||
"php-flasher/flasher-notyf-symfony": "@dev",
|
||||
"php-flasher/flasher-sweetalert": "@dev",
|
||||
"php-flasher/flasher-sweetalert-symfony": "@dev",
|
||||
"php-flasher/flasher-toastr": "@dev",
|
||||
"php-flasher/flasher-toastr-symfony": "@dev",
|
||||
"phpstan/phpstan-symfony": "^2.0",
|
||||
"symfony/console": "8.0.*",
|
||||
"symfony/dotenv": "8.0.*",
|
||||
"symfony/flex": "^2.4",
|
||||
"symfony/framework-bundle": "8.0.*",
|
||||
"symfony/monolog-bundle": "^4.0",
|
||||
"symfony/runtime": "8.0.*",
|
||||
"symfony/translation": "8.0.*",
|
||||
"symfony/twig-bundle": "8.0.*",
|
||||
"symfony/yaml": "8.0.*",
|
||||
"twig/extra-bundle": "^3.20",
|
||||
"twig/twig": "^3.20"
|
||||
},
|
||||
"require-dev": {
|
||||
"spatie/ray": "^1.41.5",
|
||||
"symfony/maker-bundle": "^1.62.1",
|
||||
"symfony/stopwatch": "7.2.*",
|
||||
"symfony/web-profiler-bundle": "7.2.*"
|
||||
"spatie/ray": "^1.41",
|
||||
"symfony/maker-bundle": "^1.62",
|
||||
"symfony/stopwatch": "8.0.*",
|
||||
"symfony/web-profiler-bundle": "8.0.*"
|
||||
},
|
||||
"config": {
|
||||
"allow-plugins": {
|
||||
@@ -85,7 +156,7 @@
|
||||
"extra": {
|
||||
"symfony": {
|
||||
"allow-contrib": false,
|
||||
"require": "7.2.*",
|
||||
"require": "8.0.*",
|
||||
"docker": false
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+1825
-5061
File diff suppressed because it is too large
Load Diff
@@ -10,8 +10,6 @@ return [
|
||||
Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true],
|
||||
Twig\Extra\TwigExtraBundle\TwigExtraBundle::class => ['all' => true],
|
||||
Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true],
|
||||
Nelmio\SecurityBundle\NelmioSecurityBundle::class => ['all' => true],
|
||||
Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true],
|
||||
Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true],
|
||||
Symfony\UX\TwigComponent\TwigComponentBundle::class => ['all' => true],
|
||||
];
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
flasher:
|
||||
# Default notification library (e.g., 'flasher', 'toastr', 'noty', etc.)
|
||||
default: flasher
|
||||
# themes: flasher, crystal, emerald, sapphire
|
||||
default: theme.minimal
|
||||
|
||||
# Path to the main JavaScript file of PHPFlasher
|
||||
main_script: '/vendor/flasher/flasher.min.js'
|
||||
@@ -19,7 +19,7 @@ flasher:
|
||||
# Global options
|
||||
options:
|
||||
# timeout in milliseconds
|
||||
timeout: 5000
|
||||
timeout: 600000
|
||||
position: 'top-right'
|
||||
|
||||
# Map Symfony session keys to PHPFlasher notification types
|
||||
@@ -33,3 +33,14 @@ flasher:
|
||||
filter:
|
||||
# Limit number of displayed notifications
|
||||
# limit: 5
|
||||
|
||||
themes:
|
||||
amazon:
|
||||
scripts:
|
||||
- '/vendor/flasher/themes/amazon/amazon.min.js'
|
||||
styles:
|
||||
- '/vendor/flasher/flasher.min.css'
|
||||
- '/vendor/flasher/themes/amazon/amazon.min.css'
|
||||
options:
|
||||
position: 'bottom-right'
|
||||
timeout: 6000
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
framework:
|
||||
mailer:
|
||||
dsn: '%env(MAILER_DSN)%'
|
||||
@@ -1,33 +1,33 @@
|
||||
nelmio_security:
|
||||
# prevents framing of the entire site
|
||||
clickjacking:
|
||||
paths:
|
||||
'^/.*': DENY
|
||||
|
||||
# disables content type sniffing for script resources
|
||||
content_type:
|
||||
nosniff: true
|
||||
|
||||
# forces Microsoft's XSS-Protection with
|
||||
# its block mode
|
||||
xss_protection:
|
||||
enabled: true
|
||||
mode_block: true
|
||||
|
||||
# Send a full URL in the `Referer` header when performing a same-origin request,
|
||||
# only send the origin of the document to secure destination (HTTPS->HTTPS),
|
||||
# and send no header to a less secure destination (HTTPS->HTTP).
|
||||
# If `strict-origin-when-cross-origin` is not supported, use `no-referrer` policy,
|
||||
# no referrer information is sent along with requests.
|
||||
referrer_policy:
|
||||
enabled: true
|
||||
policies:
|
||||
- 'no-referrer'
|
||||
- 'strict-origin-when-cross-origin'
|
||||
|
||||
csp:
|
||||
enabled: true
|
||||
|
||||
enforce:
|
||||
script-src:
|
||||
- 'self'
|
||||
# nelmio_security:
|
||||
# # prevents framing of the entire site
|
||||
# clickjacking:
|
||||
# paths:
|
||||
# '^/.*': DENY
|
||||
#
|
||||
# # disables content type sniffing for script resources
|
||||
# content_type:
|
||||
# nosniff: true
|
||||
#
|
||||
# # forces Microsoft's XSS-Protection with
|
||||
# # its block mode
|
||||
# xss_protection:
|
||||
# enabled: true
|
||||
# mode_block: true
|
||||
#
|
||||
# # Send a full URL in the `Referer` header when performing a same-origin request,
|
||||
# # only send the origin of the document to secure destination (HTTPS->HTTPS),
|
||||
# # and send no header to a less secure destination (HTTPS->HTTP).
|
||||
# # If `strict-origin-when-cross-origin` is not supported, use `no-referrer` policy,
|
||||
# # no referrer information is sent along with requests.
|
||||
# referrer_policy:
|
||||
# enabled: true
|
||||
# policies:
|
||||
# - 'no-referrer'
|
||||
# - 'strict-origin-when-cross-origin'
|
||||
#
|
||||
# csp:
|
||||
# enabled: true
|
||||
#
|
||||
# enforce:
|
||||
# script-src:
|
||||
# - 'self'
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
framework:
|
||||
notifier:
|
||||
chatter_transports:
|
||||
texter_transports:
|
||||
channel_policy:
|
||||
# use chat/slack, chat/telegram, sms/twilio or sms/nexmo
|
||||
urgent: ['email']
|
||||
high: ['email']
|
||||
medium: ['email']
|
||||
low: ['email']
|
||||
admin_recipients:
|
||||
- { email: admin@example.com }
|
||||
@@ -0,0 +1,3 @@
|
||||
framework:
|
||||
property_info:
|
||||
with_constructor_extractor: true
|
||||
@@ -1,5 +0,0 @@
|
||||
twig_component:
|
||||
anonymous_template_directory: 'components/'
|
||||
defaults:
|
||||
# Namespace & directory for components
|
||||
App\Twig\Components\: 'components/'
|
||||
@@ -1,6 +1,6 @@
|
||||
when@dev:
|
||||
web_profiler:
|
||||
toolbar: true
|
||||
toolbar: false
|
||||
intercept_redirects: false
|
||||
|
||||
framework:
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
when@dev:
|
||||
_errors:
|
||||
resource: '@FrameworkBundle/Resources/config/routing/errors.xml'
|
||||
resource: '@FrameworkBundle/Resources/config/routing/errors.php'
|
||||
prefix: /_error
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
when@dev:
|
||||
web_profiler_wdt:
|
||||
resource: '@WebProfilerBundle/Resources/config/routing/wdt.xml'
|
||||
resource: '@WebProfilerBundle/Resources/config/routing/wdt.php'
|
||||
prefix: /_wdt
|
||||
|
||||
web_profiler_profiler:
|
||||
resource: '@WebProfilerBundle/Resources/config/routing/profiler.xml'
|
||||
resource: '@WebProfilerBundle/Resources/config/routing/profiler.php'
|
||||
prefix: /_profiler
|
||||
|
||||
Generated
+8245
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "encore dev",
|
||||
"watch": "encore dev --watch",
|
||||
"build": "encore production"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@symfony/webpack-encore": "^4.0.0",
|
||||
"webpack": "^5.0.0",
|
||||
"webpack-cli": "^5.0.0",
|
||||
"webpack-notifier": "^1.15.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[524],{28:function(){console.log("PHPFlasher Symfony Demo loaded")}},function(e){var n;n=28,e(e.s=n)}]);
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"entrypoints": {
|
||||
"app": {
|
||||
"js": [
|
||||
"/build/runtime.ccfad4f9.js",
|
||||
"/build/app.f62ef15b.js"
|
||||
],
|
||||
"css": [
|
||||
"/build/app.31d6cfe0.css"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"build/app.css": "/build/app.31d6cfe0.css",
|
||||
"build/app.js": "/build/app.f62ef15b.js",
|
||||
"build/runtime.js": "/build/runtime.ccfad4f9.js"
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const demoForm = document.getElementById('notification-demo-form');
|
||||
|
||||
if (demoForm) {
|
||||
demoForm.addEventListener('submit', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const type = document.getElementById('notification-type').value;
|
||||
const title = document.getElementById('notification-title').value;
|
||||
const message = document.getElementById('notification-message').value;
|
||||
const position = document.getElementById('notification-position').value;
|
||||
const timeout = document.getElementById('notification-timeout').value;
|
||||
|
||||
// Use the PHPFlasher JavaScript API to show the notification
|
||||
window.flasher[type](message, {
|
||||
title: title,
|
||||
position: position,
|
||||
timeout: parseInt(timeout, 10)
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
+1
-1
@@ -1 +1 @@
|
||||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(require("@flasher/flasher"),require("noty")):"function"==typeof define&&define.amd?define(["@flasher/flasher","noty"],t):(e="undefined"!=typeof globalThis?globalThis:e||self).Noty=t(e.flasher,e.Noty)}(this,(function(e,t){"use strict";class s{success(e,t,s){this.flash("success",e,t,s)}error(e,t,s){this.flash("error",e,t,s)}info(e,t,s){this.flash("info",e,t,s)}warning(e,t,s){this.flash("warning",e,t,s)}flash(e,t,s,o){if("object"==typeof e?(e=(o=e).type,t=o.message,s=o.title):"object"==typeof t?(t=(o=t).message,s=o.title):"object"==typeof s&&(s=(o=s).title),void 0===t)throw new Error("message option is required");const n={type:e,message:t,title:s||e,options:o||{},metadata:{plugin:""}};this.renderOptions(o||{}),this.renderEnvelopes([n])}}const o=new class extends s{renderEnvelopes(e){e.forEach((e=>{var s;const o=Object.assign({text:e.message,type:e.type},e.options),n=new t(o);n.show(),null===(s=n.layoutDom)||void 0===s||(s.dataset.turboTemporary="")}))}renderOptions(e){t.overrideDefaults(Object.assign({timeout:e.timeout||5e3},e))}};return e.addPlugin("noty",o),o}));
|
||||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(require("@flasher/flasher"),require("noty")):"function"==typeof define&&define.amd?define(["@flasher/flasher","noty"],t):(e="undefined"!=typeof globalThis?globalThis:e||self).Noty=t(e.flasher,e.Noty)}(this,(function(e,t){"use strict";class o{success(e,t,o){this.flash("success",e,t,o)}error(e,t,o){this.flash("error",e,t,o)}info(e,t,o){this.flash("info",e,t,o)}warning(e,t,o){this.flash("warning",e,t,o)}flash(e,t,o,s){let n,i,l,a={};if("object"==typeof e?(a=Object.assign({},e),n=a.type,i=a.message,l=a.title,delete a.type,delete a.message,delete a.title):"object"==typeof t?(a=Object.assign({},t),n=e,i=a.message,l=a.title,delete a.message,delete a.title):(n=e,i=t,null==o?(l=void 0,a=s||{}):"string"==typeof o?(l=o,a=s||{}):"object"==typeof o&&(a=Object.assign({},o),"title"in a?(l=a.title,delete a.title):l=void 0,s&&"object"==typeof s&&(a=Object.assign(Object.assign({},a),s)))),!n)throw new Error("Type is required for notifications");if(null==i)throw new Error("Message is required for notifications");null==l&&(l=n.charAt(0).toUpperCase()+n.slice(1));const r={type:n,message:i,title:l,options:a,metadata:{plugin:""}};this.renderOptions({}),this.renderEnvelopes([r])}}const s=new class extends o{constructor(){super(...arguments),this.defaultOptions={timeout:1e4}}renderEnvelopes(e){(null==e?void 0:e.length)&&e.forEach((e=>{var o,s,n,i;try{const l=Object.assign({text:e.message,type:e.type},this.defaultOptions);e.options&&Object.assign(l,e.options);const a={onShow:null===(o=l.callbacks)||void 0===o?void 0:o.onShow,onClick:null===(s=l.callbacks)||void 0===s?void 0:s.onClick,onClose:null===(n=l.callbacks)||void 0===n?void 0:n.onClose,onHover:null===(i=l.callbacks)||void 0===i?void 0:i.onHover};l.callbacks=Object.assign(Object.assign({},l.callbacks),{onShow:()=>{var t;this.dispatchEvent("flasher:noty:show",e),null===(t=a.onShow)||void 0===t||t.call(a)},onClick:()=>{var t;this.dispatchEvent("flasher:noty:click",e),null===(t=a.onClick)||void 0===t||t.call(a)},onClose:()=>{var t;this.dispatchEvent("flasher:noty:close",e),null===(t=a.onClose)||void 0===t||t.call(a)},onHover:()=>{var t;this.dispatchEvent("flasher:noty:hover",e),null===(t=a.onHover)||void 0===t||t.call(a)}});const r=new t(l);r.show();const c=r.layoutDom;c&&"object"==typeof c.dataset&&(c.dataset.turboTemporary="")}catch(t){console.error("PHPFlasher Noty: Error rendering notification",t,e)}}))}dispatchEvent(e,t){window.dispatchEvent(new CustomEvent(e,{detail:{envelope:t}}))}renderOptions(e){e&&(Object.assign(this.defaultOptions,e),t.overrideDefaults(this.defaultOptions))}};return e.addPlugin("noty",s),s}));
|
||||
|
||||
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(require("@flasher/flasher"),require("sweetalert2")):"function"==typeof define&&define.amd?define(["@flasher/flasher","sweetalert2"],t):(e="undefined"!=typeof globalThis?globalThis:e||self).sweetalert=t(e.flasher,e.Swal)}(this,(function(e,t){"use strict";function s(e,t,s,n){return new(s||(s=Promise))((function(i,r){function o(e){try{a(n.next(e))}catch(e){r(e)}}function l(e){try{a(n.throw(e))}catch(e){r(e)}}function a(e){var t;e.done?i(e.value):(t=e.value,t instanceof s?t:new s((function(e){e(t)}))).then(o,l)}a((n=n.apply(e,t||[])).next())}))}"function"==typeof SuppressedError&&SuppressedError;class n{success(e,t,s){this.flash("success",e,t,s)}error(e,t,s){this.flash("error",e,t,s)}info(e,t,s){this.flash("info",e,t,s)}warning(e,t,s){this.flash("warning",e,t,s)}flash(e,t,s,n){if("object"==typeof e?(e=(n=e).type,t=n.message,s=n.title):"object"==typeof t?(t=(n=t).message,s=n.title):"object"==typeof s&&(s=(n=s).title),void 0===t)throw new Error("message option is required");const i={type:e,message:t,title:s||e,options:n||{},metadata:{plugin:""}};this.renderOptions(n||{}),this.renderEnvelopes([i])}}const i=new class extends n{renderEnvelopes(e){return s(this,void 0,void 0,(function*(){for(const t of e)yield this.renderEnvelope(t)}))}renderOptions(e){this.sweetalert=this.sweetalert||t.mixin(Object.assign({timer:e.timer||5e3,timerProgressBar:e.timerProgressBar||!0},e)),document.addEventListener("turbo:before-cache",(()=>{var e;t.isVisible()&&(null===(e=t.getPopup())||void 0===e||e.style.setProperty("animation-duration","0ms"),t.close())}))}renderEnvelope(e){return s(this,void 0,void 0,(function*(){var t;let{options:s}=e;s=Object.assign(Object.assign({},s),{icon:(null==s?void 0:s.icon)||e.type,text:(null==s?void 0:s.text)||e.message}),yield null===(t=this.sweetalert)||void 0===t?void 0:t.fire(s).then((t=>{window.dispatchEvent(new CustomEvent("flasher:sweetalert:promise",{detail:{promise:t,envelope:e}}))}))}))}};return e.addPlugin("sweetalert",i),i}));
|
||||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(require("@flasher/flasher"),require("sweetalert2")):"function"==typeof define&&define.amd?define(["@flasher/flasher","sweetalert2"],t):(e="undefined"!=typeof globalThis?globalThis:e||self).sweetalert=t(e.flasher,e.Swal)}(this,(function(e,t){"use strict";function r(e,t,r,s){return new(r||(r=Promise))((function(i,n){function o(e){try{a(s.next(e))}catch(e){n(e)}}function l(e){try{a(s.throw(e))}catch(e){n(e)}}function a(e){var t;e.done?i(e.value):(t=e.value,t instanceof r?t:new r((function(e){e(t)}))).then(o,l)}a((s=s.apply(e,t||[])).next())}))}"function"==typeof SuppressedError&&SuppressedError;class s{success(e,t,r){this.flash("success",e,t,r)}error(e,t,r){this.flash("error",e,t,r)}info(e,t,r){this.flash("info",e,t,r)}warning(e,t,r){this.flash("warning",e,t,r)}flash(e,t,r,s){let i,n,o,l={};if("object"==typeof e?(l=Object.assign({},e),i=l.type,n=l.message,o=l.title,delete l.type,delete l.message,delete l.title):"object"==typeof t?(l=Object.assign({},t),i=e,n=l.message,o=l.title,delete l.message,delete l.title):(i=e,n=t,null==r?(o=void 0,l=s||{}):"string"==typeof r?(o=r,l=s||{}):"object"==typeof r&&(l=Object.assign({},r),"title"in l?(o=l.title,delete l.title):o=void 0,s&&"object"==typeof s&&(l=Object.assign(Object.assign({},l),s)))),!i)throw new Error("Type is required for notifications");if(null==n)throw new Error("Message is required for notifications");null==o&&(o=i.charAt(0).toUpperCase()+i.slice(1));const a={type:i,message:n,title:o,options:l,metadata:{plugin:""}};this.renderOptions({}),this.renderEnvelopes([a])}}const i=new class extends s{renderEnvelopes(e){return r(this,void 0,void 0,(function*(){this.sweetalert||this.initializeSweetAlert();try{for(const t of e)yield this.renderEnvelope(t)}catch(e){console.error("PHPFlasher SweetAlert: Error rendering envelopes",e)}}))}renderOptions(e){try{this.sweetalert=this.sweetalert||t.mixin(Object.assign({timer:e.timer||1e4,timerProgressBar:e.timerProgressBar||!0},e)),this.setupTurboCompatibility()}catch(e){console.error("PHPFlasher SweetAlert: Error applying options",e)}}renderEnvelope(e){return r(this,void 0,void 0,(function*(){var t;try{let{options:r}=e;r=Object.assign(Object.assign({},r),{icon:(null==r?void 0:r.icon)||e.type,text:(null==r?void 0:r.text)||e.message});const s=yield null===(t=this.sweetalert)||void 0===t?void 0:t.fire(r);this.dispatchResultEvent(s,e)}catch(t){console.error("PHPFlasher SweetAlert: Error rendering envelope",t,e)}}))}initializeSweetAlert(){this.sweetalert||this.renderOptions({timer:1e4,timerProgressBar:!0})}setupTurboCompatibility(){document.addEventListener("turbo:before-cache",(()=>{if(t.isVisible()){const e=t.getPopup();e&&e.style.setProperty("animation-duration","0ms"),t.close()}}))}dispatchResultEvent(e,t){e&&window.dispatchEvent(new CustomEvent("flasher:sweetalert:promise",{detail:{promise:e,envelope:t}}))}};return e.addPlugin("sweetalert",i),i}));
|
||||
|
||||
@@ -1 +1 @@
|
||||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(require("@flasher/flasher"),require("toastr")):"function"==typeof define&&define.amd?define(["@flasher/flasher","toastr"],t):(e="undefined"!=typeof globalThis?globalThis:e||self).toastr=t(e.flasher,e.toastr)}(this,(function(e,t){"use strict";class s{success(e,t,s){this.flash("success",e,t,s)}error(e,t,s){this.flash("error",e,t,s)}info(e,t,s){this.flash("info",e,t,s)}warning(e,t,s){this.flash("warning",e,t,s)}flash(e,t,s,r){if("object"==typeof e?(e=(r=e).type,t=r.message,s=r.title):"object"==typeof t?(t=(r=t).message,s=r.title):"object"==typeof s&&(s=(r=s).title),void 0===t)throw new Error("message option is required");const o={type:e,message:t,title:s||e,options:r||{},metadata:{plugin:""}};this.renderOptions(r||{}),this.renderEnvelopes([o])}}const r=new class extends s{renderEnvelopes(e){e.forEach((e=>{const{message:s,title:r,type:o,options:i}=e,n=t[o](s,r,i);n&&n.parent().attr("data-turbo-temporary","")}))}renderOptions(e){t.options=Object.assign({timeOut:e.timeOut||5e3,progressBar:e.progressBar||!0},e)}};return e.addPlugin("toastr",r),r}));
|
||||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(require("@flasher/flasher"),require("toastr")):"function"==typeof define&&define.amd?define(["@flasher/flasher","toastr"],t):(e="undefined"!=typeof globalThis?globalThis:e||self).toastr=t(e.flasher,e.toastr)}(this,(function(e,t){"use strict";class s{success(e,t,s){this.flash("success",e,t,s)}error(e,t,s){this.flash("error",e,t,s)}info(e,t,s){this.flash("info",e,t,s)}warning(e,t,s){this.flash("warning",e,t,s)}flash(e,t,s,o){let i,r,n,l={};if("object"==typeof e?(l=Object.assign({},e),i=l.type,r=l.message,n=l.title,delete l.type,delete l.message,delete l.title):"object"==typeof t?(l=Object.assign({},t),i=e,r=l.message,n=l.title,delete l.message,delete l.title):(i=e,r=t,null==s?(n=void 0,l=o||{}):"string"==typeof s?(n=s,l=o||{}):"object"==typeof s&&(l=Object.assign({},s),"title"in l?(n=l.title,delete l.title):n=void 0,o&&"object"==typeof o&&(l=Object.assign(Object.assign({},l),o)))),!i)throw new Error("Type is required for notifications");if(null==r)throw new Error("Message is required for notifications");null==n&&(n=i.charAt(0).toUpperCase()+i.slice(1));const a={type:i,message:r,title:n,options:l,metadata:{plugin:""}};this.renderOptions({}),this.renderEnvelopes([a])}}const o=new class extends s{renderEnvelopes(e){(null==e?void 0:e.length)&&this.isDependencyAvailable()&&e.forEach((e=>{try{const{message:s,title:o,type:i,options:r}=e,n=Object.assign(Object.assign({},r),{onShown:()=>{var t;this.dispatchEvent("flasher:toastr:show",e),null===(t=null==r?void 0:r.onShown)||void 0===t||t.call(r)},onclick:()=>{var t;this.dispatchEvent("flasher:toastr:click",e),null===(t=null==r?void 0:r.onclick)||void 0===t||t.call(r)},onCloseClick:()=>{var t;this.dispatchEvent("flasher:toastr:close",e),null===(t=null==r?void 0:r.onCloseClick)||void 0===t||t.call(r)},onHidden:()=>{var t;this.dispatchEvent("flasher:toastr:hidden",e),null===(t=null==r?void 0:r.onHidden)||void 0===t||t.call(r)}}),l=t[i](s,o,n);if(l&&l.parent)try{const e=l.parent();e&&"function"==typeof e.attr&&e.attr("data-turbo-temporary","")}catch(e){console.error("PHPFlasher Toastr: Error setting Turbo compatibility",e)}}catch(t){console.error("PHPFlasher Toastr: Error rendering notification",t,e)}}))}dispatchEvent(e,t){window.dispatchEvent(new CustomEvent(e,{detail:{envelope:t}}))}renderOptions(e){if(this.isDependencyAvailable())try{t.options=Object.assign({timeOut:e.timeOut||1e4,progressBar:e.progressBar||!0},e)}catch(e){console.error("PHPFlasher Toastr: Error applying options",e)}}isDependencyAvailable(){return!(!window.jQuery&&!window.$)||(console.error("PHPFlasher Toastr: jQuery is required but not loaded. Make sure jQuery is loaded before using Toastr."),!1)}};return e.addPlugin("toastr",o),o}));
|
||||
|
||||
+18
-2
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+44
-9
@@ -1,17 +1,52 @@
|
||||
{
|
||||
"/vendor/flasher/flasher.min.js": "/vendor/flasher/flasher.min.js?id=9a255a6680873c0d5fc3d394a2ba3195",
|
||||
"/vendor/flasher/flasher.min.css": "/vendor/flasher/flasher.min.css?id=7a96e40c68626198d5128ad2fb5d77e0",
|
||||
"/vendor/flasher/flasher.min.js": "/vendor/flasher/flasher.min.js?id=aa16aaa1cf4481da81e2392eed0a5804",
|
||||
"/vendor/flasher/flasher.min.css": "/vendor/flasher/flasher.min.css?id=0d92a4c6a11d829ad5232f66b08ffe82",
|
||||
"/vendor/flasher/themes/amazon/amazon.min.css": "/vendor/flasher/themes/amazon/amazon.min.css?id=9ee70f25ed683a1a06c96832e53ae372",
|
||||
"/vendor/flasher/themes/amazon/amazon.min.js": "/vendor/flasher/themes/amazon/amazon.min.js?id=818ae079cef66072237504a6292015fe",
|
||||
"/vendor/flasher/themes/sapphire/sapphire.min.css": "/vendor/flasher/themes/sapphire/sapphire.min.css?id=f7b4efc7b645ee792dacd4438fdc4ea3",
|
||||
"/vendor/flasher/themes/sapphire/sapphire.min.js": "/vendor/flasher/themes/sapphire/sapphire.min.js?id=6b9266d751da3dff9201fdd70d86c42a",
|
||||
"/vendor/flasher/themes/google/google.min.js": "/vendor/flasher/themes/google/google.min.js?id=ce9d22b65c40f5537bd3dca88029bfa8",
|
||||
"/vendor/flasher/themes/google/google.min.css": "/vendor/flasher/themes/google/google.min.css?id=b5f06fb2a4795ce361e94113d3b91822",
|
||||
"/vendor/flasher/themes/flasher/flasher.min.js": "/vendor/flasher/themes/flasher/flasher.min.js?id=369290828dc5b9dc18b4e768b7855e2b",
|
||||
"/vendor/flasher/themes/flasher/flasher.min.css": "/vendor/flasher/themes/flasher/flasher.min.css?id=afe8be6f2c545ee55168ccc601d60a27",
|
||||
"/vendor/flasher/themes/aurora/aurora.min.css": "/vendor/flasher/themes/aurora/aurora.min.css?id=c147c3dce846ce387a2360fb7c5ef317",
|
||||
"/vendor/flasher/themes/aurora/aurora.min.js": "/vendor/flasher/themes/aurora/aurora.min.js?id=7215e6d20cb0a7291004907beaf3b8c3",
|
||||
"/vendor/flasher/themes/crystal/crystal.min.css": "/vendor/flasher/themes/crystal/crystal.min.css?id=22d1ac60ba71b99d33f06d8860542bea",
|
||||
"/vendor/flasher/themes/crystal/crystal.min.js": "/vendor/flasher/themes/crystal/crystal.min.js?id=d0b16d7675876adb142ce7215ed5aa59",
|
||||
"/vendor/flasher/themes/shared/shared.min.js": "/vendor/flasher/themes/shared/shared.min.js?id=6099d7536c1f8046d778d61dfa40004c",
|
||||
"/vendor/flasher/themes/minimal/minimal.min.css": "/vendor/flasher/themes/minimal/minimal.min.css?id=ece6c8d8425a37426f2953e7d771cd34",
|
||||
"/vendor/flasher/themes/minimal/minimal.min.js": "/vendor/flasher/themes/minimal/minimal.min.js?id=0a94dfe76fb9b0a2dbf60a3661b06bfb",
|
||||
"/vendor/flasher/themes/ios/ios.min.js": "/vendor/flasher/themes/ios/ios.min.js?id=4fc66d5cef6a7d30c5e94c4ababe21ea",
|
||||
"/vendor/flasher/themes/ios/ios.min.css": "/vendor/flasher/themes/ios/ios.min.css?id=9680ce2ce92ac435c99a40e599d2e775",
|
||||
"/vendor/flasher/themes/onyx/onyx.min.css": "/vendor/flasher/themes/onyx/onyx.min.css?id=eff8e7447767c39298a9c3565a917d79",
|
||||
"/vendor/flasher/themes/onyx/onyx.min.js": "/vendor/flasher/themes/onyx/onyx.min.js?id=e15080237480b663ad2ab817e254fa9f",
|
||||
"/vendor/flasher/themes/amber/amber.min.js": "/vendor/flasher/themes/amber/amber.min.js?id=a5147d1108e4752a0ebb492b0e26ed81",
|
||||
"/vendor/flasher/themes/amber/amber.min.css": "/vendor/flasher/themes/amber/amber.min.css?id=20aa374b7ede682a6a0eb00c19a0013c",
|
||||
"/vendor/flasher/themes/facebook/facebook.min.js": "/vendor/flasher/themes/facebook/facebook.min.js?id=5a82f0ed6b06975fedabd8f0f8eb3eed",
|
||||
"/vendor/flasher/themes/facebook/facebook.min.css": "/vendor/flasher/themes/facebook/facebook.min.css?id=edfbad59ded6831073a0d08a799757fd",
|
||||
"/vendor/flasher/themes/neon/neon.min.css": "/vendor/flasher/themes/neon/neon.min.css?id=38716f3f934f720ac34fb6617d5dc674",
|
||||
"/vendor/flasher/themes/neon/neon.min.js": "/vendor/flasher/themes/neon/neon.min.js?id=3188b54684a7193acffa63d2305468a0",
|
||||
"/vendor/flasher/themes/slack/slack.min.js": "/vendor/flasher/themes/slack/slack.min.js?id=cd54c7e2570e9784e03d6772e9ae4e8e",
|
||||
"/vendor/flasher/themes/slack/slack.min.css": "/vendor/flasher/themes/slack/slack.min.css?id=4fa1fe1bdca7c256f225e9f4c2e6d779",
|
||||
"/vendor/flasher/themes/jade/jade.min.js": "/vendor/flasher/themes/jade/jade.min.js?id=664998188449eebf74b7c1924f1a129d",
|
||||
"/vendor/flasher/themes/jade/jade.min.css": "/vendor/flasher/themes/jade/jade.min.css?id=b140ea3056bc6eaa860c891bedf16818",
|
||||
"/vendor/flasher/themes/material/material.min.js": "/vendor/flasher/themes/material/material.min.js?id=b5b83b804f0ce8135899f86453741128",
|
||||
"/vendor/flasher/themes/material/material.min.css": "/vendor/flasher/themes/material/material.min.css?id=f0327e5645332c10d957fff6af1220fc",
|
||||
"/vendor/flasher/themes/ruby/ruby.min.css": "/vendor/flasher/themes/ruby/ruby.min.css?id=faffa15686ab77a5f8988d1b8cc54650",
|
||||
"/vendor/flasher/themes/ruby/ruby.min.js": "/vendor/flasher/themes/ruby/ruby.min.js?id=5d0262a53a5d9bb8ab0eadaceadfc7b8",
|
||||
"/vendor/flasher/themes/emerald/emerald.min.css": "/vendor/flasher/themes/emerald/emerald.min.css?id=4e346793d433693b3fdfd9de46d05590",
|
||||
"/vendor/flasher/themes/emerald/emerald.min.js": "/vendor/flasher/themes/emerald/emerald.min.js?id=317b24bd9eee938ebd9c3221417fd27c",
|
||||
"/vendor/flasher/mint.css": "/vendor/flasher/mint.css?id=348f135fff639305dde0005c647c1d20",
|
||||
"/vendor/flasher/flasher-noty.min.js": "/vendor/flasher/flasher-noty.min.js?id=d7d160fe2043e65250dfcaa5590d2e28",
|
||||
"/vendor/flasher/flasher-noty.min.js": "/vendor/flasher/flasher-noty.min.js?id=6a5a2c112c3192328d30b740397f84ed",
|
||||
"/vendor/flasher/noty.css": "/vendor/flasher/noty.css?id=bf51111a785e04cc8c86a7786e855484",
|
||||
"/vendor/flasher/noty.min.js": "/vendor/flasher/noty.min.js?id=840a31ddb720ff391cfc386c009d3422",
|
||||
"/vendor/flasher/flasher-notyf.min.js": "/vendor/flasher/flasher-notyf.min.js?id=d8778adb84f0e2521d413c9ca995309c",
|
||||
"/vendor/flasher/flasher-notyf.min.css": "/vendor/flasher/flasher-notyf.min.css?id=53f57ecf59a7045f8029243bde3ed054",
|
||||
"/vendor/flasher/flasher-notyf.min.js": "/vendor/flasher/flasher-notyf.min.js?id=deabfa48c70419ebd3b2b28fcfe7b8c5",
|
||||
"/vendor/flasher/flasher-notyf.min.css": "/vendor/flasher/flasher-notyf.min.css?id=a68d410be6df5aaa1dd8ed3a2798d390",
|
||||
"/vendor/flasher/toastr.min.css": "/vendor/flasher/toastr.min.css?id=f284028c678041d687c6f1be6968f68a",
|
||||
"/vendor/flasher/flasher-toastr.min.js": "/vendor/flasher/flasher-toastr.min.js?id=e0d38991a82d544068555ff7c2a2339b",
|
||||
"/vendor/flasher/flasher-toastr.min.js": "/vendor/flasher/flasher-toastr.min.js?id=8285b44e43242b12946afdf304df9e83",
|
||||
"/vendor/flasher/toastr.min.js": "/vendor/flasher/toastr.min.js?id=8ee1218b09fb02d43fcf0b84e30637ad",
|
||||
"/vendor/flasher/jquery.min.js": "/vendor/flasher/jquery.min.js?id=2c872dbe60f4ba70fb85356113d8b35e",
|
||||
"/vendor/flasher/sweetalert2.min.js": "/vendor/flasher/sweetalert2.min.js?id=52e4f161dbe2cf71c99dfef9f94fb1ff",
|
||||
"/vendor/flasher/sweetalert2.min.css": "/vendor/flasher/sweetalert2.min.css?id=a45abfe01a51ef4b1a068fb739f4e540",
|
||||
"/vendor/flasher/flasher-sweetalert.min.js": "/vendor/flasher/flasher-sweetalert.min.js?id=4ede7e66493a3432961bb00ce83dd4da"
|
||||
"/vendor/flasher/sweetalert2.min.js": "/vendor/flasher/sweetalert2.min.js?id=bba3afcfe7dcc339fa25fad49842c2bf",
|
||||
"/vendor/flasher/sweetalert2.min.css": "/vendor/flasher/sweetalert2.min.css?id=83b54381abbed7676c22f411eba2c61d",
|
||||
"/vendor/flasher/flasher-sweetalert.min.js": "/vendor/flasher/flasher-sweetalert.min.js?id=471a0b1aec6d6adc8e42a7c5dfcf0a93"
|
||||
}
|
||||
+1
-1
File diff suppressed because one or more lines are too long
+2
-2
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
!function(n,e){"object"==typeof exports&&"undefined"!=typeof module?e(require("@flasher/flasher")):"function"==typeof define&&define.amd?define(["@flasher/flasher"],e):e((n="undefined"!=typeof globalThis?globalThis:n||self).flasher)}(this,(function(n){"use strict";const e={sm:16,md:20,lg:24},s={success:"M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z",error:"M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10 10-4.47 10-10S17.53 2 12 2zm5 13.59L15.59 17 12 13.41 8.41 17 7 15.59 10.59 12 7 8.41 8.41 7 12 10.59 15.59 7 17 8.41 13.41 12 17 15.59z",warning:"M12 5.99L19.53 19H4.47L12 5.99M12 2L1 21h22L12 2zm1 14h-2v2h2v-2zm0-6h-2v4h2v-4z",info:"M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z",close:"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"};function r(n,r={}){const{size:i="md",className:t=""}=r,a="number"==typeof i?i:e[i],o=s[n];if(!o)return"";return`<svg${t?` class="${t}"`:""} viewBox="0 0 24 24" width="${a}" height="${a}" aria-hidden="true"><path fill="currentColor" d="${o}"/></svg>`}const i="fl-close",t=n=>`fl-${n}`,a=n=>`fl-${n}`,o={success:"Success",error:"Error",warning:"Warning",info:"Information"},l={success:"Success!",error:"Problem",warning:"Warning",info:"Information"},c={render:n=>{const{type:e,message:s}=n,c=l[e]||o[e]||"Alert";return`\n <div class="${a("amazon")} ${t(e)}" ${function(n){const e=function(n){const e="error"===n||"warning"===n;return{role:e?"alert":"status",ariaLive:e?"assertive":"polite",ariaAtomic:"true"}}(n);return`role="${e.role}" aria-live="${e.ariaLive}" aria-atomic="${e.ariaAtomic}"`}(e)}>\n <div class="fl-amazon-alert">\n <div class="fl-alert-content">\n <div class="fl-icon-container">\n ${function(n,e={}){return"success"===n||"error"===n||"warning"===n||"info"===n?r(n,e):""}(e,{size:"lg"})}\n </div>\n <div class="fl-text-content">\n <div class="fl-alert-title">${c}</div>\n <div class="fl-alert-message">${s}</div>\n </div>\n </div>\n <div class="fl-alert-actions">\n <button class="${i}" ${function(n){return`aria-label="Close ${n} message"`}(e)}>\n ${function(n={}){return r("close",Object.assign({size:"sm"},n))}()}\n </button>\n </div>\n </div>\n </div>`}};n.addTheme("amazon",c)}));
|
||||
@@ -0,0 +1 @@
|
||||
.fl-amber{--amber-bg-light:#fff;--amber-bg-dark:#1e293b;--amber-text-light:#4b5563;--amber-text-dark:#f1f5f9;--amber-shadow:0 5px 15px rgba(0,0,0,.08);--amber-shadow-dark:0 5px 15px rgba(0,0,0,.2);--amber-border-radius:4px;--amber-success:#10b981;--amber-info:#3b82f6;--amber-warning:#f59e0b;--amber-error:#ef4444}@keyframes amberIn{0%{opacity:0;transform:translateY(-12px)}to{opacity:1;transform:translateY(0)}}.fl-amber{animation:amberIn .3s ease-out;background-color:var(--amber-bg-light);border-radius:var(--amber-border-radius) var(--amber-border-radius) 0 0;box-shadow:var(--amber-shadow);color:var(--amber-text-light);font-family:var(--fl-font),serif;margin:.6rem 0;padding:.85rem 1rem;position:relative;will-change:transform,opacity}.fl-amber .fl-content{align-items:center;display:flex}.fl-amber .fl-icon{font-size:1.85em;margin-right:.8rem}.fl-amber .fl-text{flex:1}.fl-amber .fl-message{font-size:.875em;line-height:1.4}.fl-amber .fl-close{background:none;border:none;color:currentColor;cursor:pointer;flex-shrink:0;font-size:1.15rem;margin-left:1rem;opacity:.6;padding:.25rem;touch-action:manipulation;transition:opacity .2s}.fl-amber .fl-close:focus,.fl-amber .fl-close:hover{opacity:1}.fl-amber .fl-progress-bar{bottom:0;height:3px;left:0;overflow:hidden;position:absolute;right:0}.fl-amber .fl-progress-bar .fl-progress{height:100%;width:100%}.fl-amber.fl-success .fl-close{color:var(--amber-success)}.fl-amber.fl-info .fl-close{color:var(--amber-info)}.fl-amber.fl-warning .fl-close{color:var(--amber-warning)}.fl-amber.fl-error .fl-close{color:var(--amber-error)}.fl-amber.fl-rtl{direction:rtl}.fl-amber.fl-rtl .fl-icon{margin-left:.8rem;margin-right:0}.fl-amber.fl-rtl .fl-close{margin-left:0;margin-right:1rem}.fl-amber.fl-rtl .fl-progress .fl-progress{transform-origin:right center}@media (prefers-reduced-motion:reduce){.fl-amber{animation:none}}.fl-amber.fl-auto-dark,body.fl-dark .fl-amber,html.fl-dark .fl-amber{background-color:var(--amber-bg-dark);box-shadow:var(--amber-shadow-dark);color:var(--amber-text-dark)}
|
||||
@@ -0,0 +1 @@
|
||||
!function(e,s){"object"==typeof exports&&"undefined"!=typeof module?s(require("@flasher/flasher")):"function"==typeof define&&define.amd?define(["@flasher/flasher"],s):s((e="undefined"!=typeof globalThis?globalThis:e||self).flasher)}(this,(function(e){"use strict";const s="fl-content",i="fl-message",n="fl-text",a="fl-icon",r="fl-close",t="fl-progress-bar",l="fl-progress",o=e=>`fl-${e}`,f=e=>`fl-${e}`,c={render:e=>{const{type:c,message:d}=e;return`\n <div class="${f("amber")} ${o(c)}" ${function(e){const s=function(e){const s="error"===e||"warning"===e;return{role:s?"alert":"status",ariaLive:s?"assertive":"polite",ariaAtomic:"true"}}(e);return`role="${s.role}" aria-live="${s.ariaLive}" aria-atomic="${s.ariaAtomic}"`}(c)}>\n <div class="${s}">\n <div class="${a}"></div>\n <div class="${n}">\n <div class="${i}">${d}</div>\n </div>\n <button class="${r}" ${function(e){return`aria-label="Close ${e} message"`}(c)}>×</button>\n </div>\n <div class="${t}">\n <div class="${l}"></div>\n </div>\n </div>`}};e.addTheme("amber",c)}));
|
||||
@@ -0,0 +1 @@
|
||||
.fl-aurora{--aurora-bg-light:#fff;--aurora-bg-dark:#14141c;--aurora-text-light:#1e293b;--aurora-text-dark:#f8fafc;--aurora-shadow:0 8px 25px rgba(0,0,0,.08);--aurora-shadow-dark:0 10px 30px rgba(0,0,0,.16);--aurora-border-radius:4px;--aurora-blur:15px;--aurora-success-gradient:linear-gradient(135deg,rgba(16,185,129,.08),rgba(16,185,129,.2));--aurora-info-gradient:linear-gradient(135deg,rgba(59,130,246,.08),rgba(59,130,246,.2));--aurora-warning-gradient:linear-gradient(135deg,rgba(245,158,11,.08),rgba(245,158,11,.2));--aurora-error-gradient:linear-gradient(135deg,rgba(239,68,68,.08),rgba(239,68,68,.2));--aurora-success:#10b981;--aurora-info:#3b82f6;--aurora-warning:#f59e0b;--aurora-error:#ef4444}@keyframes auroraFadeIn{0%{opacity:0;transform:translateY(-12px) scale(.98)}to{opacity:1;transform:translateY(0) scale(1)}}.fl-aurora{animation:auroraFadeIn .35s cubic-bezier(.21,1.02,.73,1);backdrop-filter:blur(var(--aurora-blur));-webkit-backdrop-filter:blur(var(--aurora-blur));background-color:var(--aurora-bg-light);border-radius:var(--aurora-border-radius) var(--aurora-border-radius) 0 0;box-shadow:var(--aurora-shadow);color:var(--aurora-text-light);font-family:var(--fl-font),sans-serif;margin:10px 0;overflow:hidden;padding:16px 18px;position:relative;will-change:transform,opacity}.fl-aurora:before{border-radius:inherit;content:"";inset:0;opacity:.8;position:absolute;z-index:0}.fl-aurora .fl-content{align-items:center;display:flex;position:relative;z-index:1}.fl-aurora .fl-message{flex:1;font-size:.9375rem;font-weight:500;line-height:1.5;margin-right:10px}.fl-aurora .fl-close{align-items:center;background:rgba(0,0,0,.05);border:none;border-radius:50%;color:inherit;cursor:pointer;display:flex;flex-shrink:0;font-size:1rem;height:28px;justify-content:center;opacity:.7;transition:all .2s ease;width:28px}.fl-aurora .fl-close:focus,.fl-aurora .fl-close:hover{background:rgba(0,0,0,.1);opacity:1}.fl-aurora .fl-progress-bar{border-radius:6px;bottom:2px;height:3px;left:2px;opacity:.7;overflow:hidden;position:absolute;right:2px;z-index:1}.fl-aurora .fl-progress{height:100%;width:100%}.fl-aurora.fl-success:before{background:var(--aurora-success-gradient)}.fl-aurora.fl-success .fl-progress{background-color:var(--aurora-success)}.fl-aurora.fl-info:before{background:var(--aurora-info-gradient)}.fl-aurora.fl-info .fl-progress{background-color:var(--aurora-info)}.fl-aurora.fl-warning:before{background:var(--aurora-warning-gradient)}.fl-aurora.fl-warning .fl-progress{background-color:var(--aurora-warning)}.fl-aurora.fl-error:before{background:var(--aurora-error-gradient)}.fl-aurora.fl-error .fl-progress{background-color:var(--aurora-error)}.fl-aurora.fl-rtl{direction:rtl}.fl-aurora.fl-rtl .fl-message{margin-left:10px;margin-right:0}.fl-aurora.fl-rtl .fl-progress{transform-origin:right center}@media (prefers-reduced-motion:reduce){.fl-aurora{animation:none}}.fl-aurora.fl-auto-dark,body.fl-dark .fl-aurora,html.fl-dark .fl-aurora{background-color:var(--aurora-bg-dark);box-shadow:var(--aurora-shadow-dark);color:var(--aurora-text-dark)}.fl-aurora.fl-auto-dark .fl-close,body.fl-dark .fl-aurora .fl-close,html.fl-dark .fl-aurora .fl-close{background:hsla(0,0%,100%,.1)}.fl-aurora.fl-auto-dark .fl-close:focus,.fl-aurora.fl-auto-dark .fl-close:hover,body.fl-dark .fl-aurora .fl-close:focus,body.fl-dark .fl-aurora .fl-close:hover,html.fl-dark .fl-aurora .fl-close:focus,html.fl-dark .fl-aurora .fl-close:hover{background:hsla(0,0%,100%,.15)}.fl-aurora.fl-auto-dark.fl-success:before,body.fl-dark .fl-aurora.fl-success:before,html.fl-dark .fl-aurora.fl-success:before{background:linear-gradient(135deg,rgba(16,185,129,.1),rgba(16,185,129,.25))}.fl-aurora.fl-auto-dark.fl-info:before,body.fl-dark .fl-aurora.fl-info:before,html.fl-dark .fl-aurora.fl-info:before{background:linear-gradient(135deg,rgba(59,130,246,.1),rgba(59,130,246,.25))}.fl-aurora.fl-auto-dark.fl-warning:before,body.fl-dark .fl-aurora.fl-warning:before,html.fl-dark .fl-aurora.fl-warning:before{background:linear-gradient(135deg,rgba(245,158,11,.1),rgba(245,158,11,.25))}.fl-aurora.fl-auto-dark.fl-error:before,body.fl-dark .fl-aurora.fl-error:before,html.fl-dark .fl-aurora.fl-error:before{background:linear-gradient(135deg,rgba(239,68,68,.1),rgba(239,68,68,.25))}
|
||||
@@ -0,0 +1 @@
|
||||
!function(e,r){"object"==typeof exports&&"undefined"!=typeof module?r(require("@flasher/flasher")):"function"==typeof define&&define.amd?define(["@flasher/flasher"],r):r((e="undefined"!=typeof globalThis?globalThis:e||self).flasher)}(this,(function(e){"use strict";const r="fl-content",s="fl-message",a="fl-close",n="fl-progress-bar",i="fl-progress",t=e=>`fl-${e}`,o=e=>`fl-${e}`,l={render:e=>{const{type:l,message:f}=e;return`\n <div class="${o("aurora")} ${t(l)}" ${function(e){const r=function(e){const r="error"===e||"warning"===e;return{role:r?"alert":"status",ariaLive:r?"assertive":"polite",ariaAtomic:"true"}}(e);return`role="${r.role}" aria-live="${r.ariaLive}" aria-atomic="${r.ariaAtomic}"`}(l)}>\n <div class="${r}">\n <div class="${s}">${f}</div>\n <button class="${a}" ${function(e){return`aria-label="Close ${e} message"`}(l)}>×</button>\n </div>\n <div class="${n}">\n <div class="${i}"></div>\n </div>\n </div>`}};e.addTheme("aurora",l)}));
|
||||
@@ -0,0 +1 @@
|
||||
.fl-crystal{--crystal-bg-light:#fff;--crystal-bg-dark:rgba(30,30,30,.95);--crystal-text-light:#2c3e50;--crystal-text-dark:hsla(0,0%,100%,.95);--crystal-shadow:rgba(0,0,0,.08);--crystal-shadow-dark:rgba(0,0,0,.25)}@keyframes crystalIn{0%{opacity:0;transform:translateY(-20px)}to{opacity:1;transform:translateY(0)}}@keyframes crystalPulse{0%{box-shadow:0 2px 8px var(--crystal-shadow)}50%{box-shadow:0 4px 12px var(--crystal-shadow)}to{box-shadow:0 2px 8px var(--crystal-shadow)}}.fl-crystal{animation:crystalIn .3s ease-out;background:var(--crystal-bg-light,var(--fl-bg-light));border-radius:var(--fl-border-radius,4px) var(--fl-border-radius,4px) 0 0;box-shadow:0 2px 8px var(--crystal-shadow);font-family:var(--fl-font),serif;margin:0 0 1rem;position:relative;transition:box-shadow .3s ease;will-change:transform,opacity}.fl-crystal:hover{animation:crystalPulse 2s ease-in-out infinite}.fl-crystal .fl-content{align-items:center;display:flex;gap:.75rem;padding:1rem 2.5rem 1rem 1rem}.fl-crystal .fl-text{flex:1}.fl-crystal .fl-message{color:var(--crystal-text-light,var(--fl-text-light));font-size:.9375rem;line-height:1.4;margin:0}.fl-crystal .fl-close{background:none;border:none;color:currentColor;cursor:pointer;font-size:1.25rem;line-height:1;opacity:.5;padding:.25rem;position:absolute;right:.75rem;top:50%;touch-action:manipulation;transform:translateY(-50%);transition:all .2s ease}.fl-crystal .fl-close:focus,.fl-crystal .fl-close:hover{opacity:1;transform:translateY(-50%) scale(1.1)}.fl-crystal .fl-progress-bar{bottom:0;height:3px;left:0;overflow:hidden;position:absolute;right:0}.fl-crystal .fl-progress-bar .fl-progress{height:100%;transform-origin:left center;width:100%}.fl-crystal.fl-success,.fl-crystal.fl-success .fl-message{color:var(--success-color,var(--fl-success))}.fl-crystal.fl-error,.fl-crystal.fl-error .fl-message{color:var(--error-color,var(--fl-error))}.fl-crystal.fl-warning,.fl-crystal.fl-warning .fl-message{color:var(--warning-color,var(--fl-warning))}.fl-crystal.fl-info,.fl-crystal.fl-info .fl-message{color:var(--info-color,var(--fl-info))}.fl-crystal.fl-rtl{direction:rtl}.fl-crystal.fl-rtl .fl-content{padding:1rem 1rem 1rem 2.5rem}.fl-crystal.fl-rtl .fl-close{left:.75rem;right:auto}.fl-crystal.fl-rtl .fl-progress .fl-progress{transform-origin:right center}@media (prefers-reduced-motion:reduce){.fl-crystal{animation:none}.fl-crystal:hover{animation:none;box-shadow:0 2px 8px var(--crystal-shadow)}}.fl-crystal.fl-auto-dark,body.fl-dark .fl-crystal,html.fl-dark .fl-crystal{background-color:var(--crystal-bg-dark,var(--fl-bg-dark));box-shadow:0 2px 8px var(--crystal-shadow-dark)}.fl-crystal.fl-auto-dark .fl-message,body.fl-dark .fl-crystal .fl-message,html.fl-dark .fl-crystal .fl-message{color:var(--crystal-text-dark,var(--fl-text-dark))}.fl-crystal.fl-auto-dark:hover,body.fl-dark .fl-crystal:hover,html.fl-dark .fl-crystal:hover{animation:none;box-shadow:0 4px 16px var(--crystal-shadow-dark)}
|
||||
@@ -0,0 +1 @@
|
||||
!function(e,s){"object"==typeof exports&&"undefined"!=typeof module?s(require("@flasher/flasher")):"function"==typeof define&&define.amd?define(["@flasher/flasher"],s):s((e="undefined"!=typeof globalThis?globalThis:e||self).flasher)}(this,(function(e){"use strict";const s="fl-content",n="fl-message",r="fl-text",t="fl-close",a="fl-progress-bar",i="fl-progress",l=e=>`fl-${e}`,o=e=>`fl-${e}`,f={render:e=>{const{type:f,message:c}=e;return`\n <div class="${o("crystal")} ${l(f)}" ${function(e){const s=function(e){const s="error"===e||"warning"===e;return{role:s?"alert":"status",ariaLive:s?"assertive":"polite",ariaAtomic:"true"}}(e);return`role="${s.role}" aria-live="${s.ariaLive}" aria-atomic="${s.ariaAtomic}"`}(f)}>\n <div class="${s}">\n <div class="${r}">\n <p class="${n}">${c}</p>\n </div>\n <button class="${t}" ${function(e){return`aria-label="Close ${e} message"`}(f)}>×</button>\n </div>\n <div class="${a}">\n <div class="${i}"></div>\n </div>\n </div>`}};e.addTheme("crystal",f)}));
|
||||
@@ -0,0 +1 @@
|
||||
.fl-emerald{--emerald-bg-light:#fff;--emerald-bg-dark:#1e1e1e;--emerald-text-light:#333;--emerald-text-dark:hsla(0,0%,100%,.9);--emerald-shadow:rgba(0,0,0,.1);--emerald-blur:8px;--emerald-success:var(--success-color,#16a085);--emerald-error:var(--error-color,#e74c3c);--emerald-warning:var(--warning-color,#f39c12);--emerald-info:var(--info-color,#3498db)}@keyframes emeraldIn{0%{opacity:0;transform:scale(.5) translateY(20px)}60%{opacity:1;transform:scale(1.1) translateY(-5px)}to{opacity:1;transform:scale(1) translateY(0)}}.fl-emerald{animation:emeraldIn .5s cubic-bezier(.23,1,.32,1);backdrop-filter:blur(var(--emerald-blur));-webkit-backdrop-filter:blur(var(--emerald-blur));background:var(--emerald-bg-light);border-radius:4px 4px 0 0;box-shadow:0 10px 20px var(--emerald-shadow);color:var(--emerald-text-light);font-family:"Inter",var(--fl-font),serif;margin:0 0 .5rem;overflow:hidden;padding:1rem 1.5rem 1rem 1rem;position:relative}.fl-emerald .fl-content{align-items:center;display:flex}.fl-emerald .fl-message{flex:1;font-size:.9rem;font-weight:500;line-height:1.4}.fl-emerald .fl-close{background:transparent;border:none;color:currentColor;cursor:pointer;font-size:1.3rem;margin-left:auto;opacity:.7;transition:opacity .2s ease}.fl-emerald .fl-close:focus,.fl-emerald .fl-close:hover{opacity:1}.fl-emerald.fl-success{color:var(--emerald-success)}.fl-emerald.fl-error{color:var(--emerald-error)}.fl-emerald.fl-warning{color:var(--emerald-warning)}.fl-emerald.fl-info{color:var(--emerald-info)}.fl-emerald.fl-rtl{direction:rtl;padding:1rem 1rem 1rem 1.5rem}.fl-emerald.fl-rtl .fl-content{flex-direction:row-reverse}.fl-emerald.fl-rtl .fl-close{margin-left:0;margin-right:auto}@media (prefers-reduced-motion:reduce){.fl-emerald{animation:none}}.fl-emerald.fl-auto-dark,body.fl-dark .fl-emerald,html.fl-dark .fl-emerald{background:var(--emerald-bg-dark)}.fl-emerald.fl-auto-dark .fl-message,body.fl-dark .fl-emerald .fl-message,html.fl-dark .fl-emerald .fl-message{color:var(--emerald-text-dark)}
|
||||
@@ -0,0 +1 @@
|
||||
!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?n(require("@flasher/flasher")):"function"==typeof define&&define.amd?define(["@flasher/flasher"],n):n((e="undefined"!=typeof globalThis?globalThis:e||self).flasher)}(this,(function(e){"use strict";const n="fl-content",t="fl-message",a="fl-close",i=e=>`fl-${e}`,r=e=>`fl-${e}`,s={render:e=>{const{type:s,message:l}=e;return`\n <div class="${r("emerald")} ${i(s)}" ${function(e){const n=function(e){const n="error"===e||"warning"===e;return{role:n?"alert":"status",ariaLive:n?"assertive":"polite",ariaAtomic:"true"}}(e);return`role="${n.role}" aria-live="${n.ariaLive}" aria-atomic="${n.ariaAtomic}"`}(s)}>\n <div class="${n}">\n <div class="${t}">${l}</div>\n <button class="${a}" ${function(e){return`aria-label="Close ${e} message"`}(s)}>×</button>\n </div>\n </div>`}};e.addTheme("emerald",s)}));
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user