mirror of
https://github.com/php-flasher/php-flasher.git
synced 2026-03-31 15:07:47 +01:00
Compare commits
390 Commits
v2.1.5
...
58123f259c
| Author | SHA1 | Date | |
|---|---|---|---|
| 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
|
||||
|
||||
|
||||
@@ -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/flasher/blob/master/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,189 @@
|
||||
#!/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
|
||||
|
||||
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
-12
@@ -22,21 +22,22 @@
|
||||
"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 +52,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
+959
-538
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)}));
|
||||
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user