You've already forked php-flasher
mirror of
https://github.com/php-flasher/php-flasher.git
synced 2026-04-05 12:32:55 +01:00
Compare commits
361 Commits
v2.1.5
...
fd65254d63
| Author | SHA1 | Date | |
|---|---|---|---|
| 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/
|
||||
@@ -17,3 +19,6 @@
|
||||
/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
|
||||
|
||||
@@ -2,6 +2,13 @@
|
||||
|
||||
## [Unreleased](https://github.com/php-flasher/php-flasher/compare/v2.1.4...2.x)
|
||||
|
||||
* 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
|
||||
|
||||
## [v2.1.3](https://github.com/php-flasher/php-flasher/compare/v2.1.2...v2.1.3) - 2025-01-25
|
||||
|
||||
* bug [#208](https://github.com/php-flasher/php-flasher/issues/208) [Flasher] Add GitHub workflow for automatic publishing of assets to NPM. See [PR #211](https://github.com/php-flasher/php-flasher/pull/211) by [ToshY](https://github.com/ToshY)
|
||||
|
||||
@@ -11,272 +11,328 @@
|
||||
</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 |
|
||||
| **26 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
|
||||
---
|
||||
|
||||
## 26 Beautiful Themes
|
||||
|
||||
PHPFlasher includes **26 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 |
|
||||
| `bootstrap` | Bootstrap style |
|
||||
| `ios` | Apple iOS notifications |
|
||||
| `slack` | Slack messaging style |
|
||||
| `material` | Google Material Design |
|
||||
| `tailwind` | Tailwind CSS inspired |
|
||||
| `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 |
|
||||
| `shadow` | Soft shadow effects |
|
||||
| `spectrum` | Colorful spectrum |
|
||||
| `sunset` | Warm sunset colors |
|
||||
| `zen` | Calm minimal design |
|
||||
|
||||
[**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)
|
||||
- [Usage & Examples](https://php-flasher.io/usage)
|
||||
- [Themes Gallery](https://php-flasher.io/themes)
|
||||
- [Livewire Integration](https://php-flasher.io/livewire)
|
||||
- [Configuration Reference](https://php-flasher.io/configuration)
|
||||
- [API Reference](https://php-flasher.io/api)
|
||||
|
||||
---
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are welcome! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
|
||||
|
||||
## 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
@@ -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,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');
|
||||
}
|
||||
}
|
||||
+11
-11
@@ -16,25 +16,25 @@
|
||||
"require": {
|
||||
"php": "^8.2",
|
||||
"inertiajs/inertia-laravel": "^2.0.1",
|
||||
"laravel/framework": "^11.43.2",
|
||||
"laravel/framework": "^12.3",
|
||||
"laravel/tinker": "^2.10.1",
|
||||
"livewire/livewire": "^3.5.20",
|
||||
"livewire/livewire": "^3.6.2",
|
||||
"php-flasher/php-flasher": "@dev",
|
||||
"spatie/laravel-csp": "^2.10.3",
|
||||
"spatie/laravel-ray": "^1.39.1"
|
||||
"spatie/laravel-ray": "^1.40.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"barryvdh/laravel-debugbar": "^3.15",
|
||||
"barryvdh/laravel-debugbar": "^3.15.2",
|
||||
"fakerphp/faker": "^1.24.1",
|
||||
"larastan/larastan": "^3.1",
|
||||
"laravel/pint": "^1.21",
|
||||
"larastan/larastan": "^3.2",
|
||||
"laravel/pint": "^1.21.2",
|
||||
"laravel/sail": "^1.41",
|
||||
"mockery/mockery": "^1.6.12",
|
||||
"nunomaduro/collision": "^8.6.1",
|
||||
"nunomaduro/collision": "^8.7.0",
|
||||
"pestphp/pest": "^3.7.4",
|
||||
"pestphp/pest-plugin-laravel": "^3.1",
|
||||
"spatie/laravel-ignition": "^2.9.1",
|
||||
"spatie/ray": "^1.41.5"
|
||||
"spatie/ray": "^1.41.6"
|
||||
},
|
||||
"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
+351
-407
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',
|
||||
// ],
|
||||
// ],
|
||||
]);
|
||||
|
||||
@@ -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,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
|
||||
Generated
+225
-239
File diff suppressed because it is too large
Load Diff
@@ -10,7 +10,7 @@ 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],
|
||||
// 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,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,6 +1,6 @@
|
||||
when@dev:
|
||||
web_profiler:
|
||||
toolbar: true
|
||||
toolbar: false
|
||||
intercept_redirects: false
|
||||
|
||||
framework:
|
||||
|
||||
@@ -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 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,n,r,l={};if("object"==typeof e?(l=Object.assign({},e),i=l.type,n=l.message,r=l.title,delete l.type,delete l.message,delete l.title):"object"==typeof t?(l=Object.assign({},t),i=e,n=l.message,r=l.title,delete l.message,delete l.title):(i=e,n=t,null==s?(r=void 0,l=o||{}):"string"==typeof s?(r=s,l=o||{}):"object"==typeof s&&(l=Object.assign({},s),"title"in l?(r=l.title,delete l.title):r=void 0,o&&"object"==typeof o&&(l=Object.assign(Object.assign({},l),o)))),!i)throw new Error("Type is required for notifications");if(null==n)throw new Error("Message is required for notifications");null==r&&(r=i.charAt(0).toUpperCase()+i.slice(1));const a={type:i,message:n,title:r,options:l,metadata:{plugin:""}};this.renderOptions({}),this.renderEnvelopes([a])}}const o=new class extends s{constructor(){super(...arguments),this.defaultOptions={timeout:1e4}}renderEnvelopes(e){(null==e?void 0:e.length)&&e.forEach((e=>{try{const s=Object.assign({text:e.message,type:e.type},this.defaultOptions);e.options&&Object.assign(s,e.options);const o=new t(s);o.show();const i=o.layoutDom;i&&"object"==typeof i.dataset&&(i.dataset.turboTemporary="")}catch(t){console.error("PHPFlasher Noty: Error rendering notification",t,e)}}))}renderOptions(e){e&&(Object.assign(this.defaultOptions,e),t.overrideDefaults(this.defaultOptions))}};return e.addPlugin("noty",o),o}));
|
||||
|
||||
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,r){let o,i,n,a={};if("object"==typeof e?(a=Object.assign({},e),o=a.type,i=a.message,n=a.title,delete a.type,delete a.message,delete a.title):"object"==typeof t?(a=Object.assign({},t),o=e,i=a.message,n=a.title,delete a.message,delete a.title):(o=e,i=t,null==s?(n=void 0,a=r||{}):"string"==typeof s?(n=s,a=r||{}):"object"==typeof s&&(a=Object.assign({},s),"title"in a?(n=a.title,delete a.title):n=void 0,r&&"object"==typeof r&&(a=Object.assign(Object.assign({},a),r)))),!o)throw new Error("Type is required for notifications");if(null==i)throw new Error("Message is required for notifications");null==n&&(n=o.charAt(0).toUpperCase()+o.slice(1));const l={type:o,message:i,title:n,options:a,metadata:{plugin:""}};this.renderOptions({}),this.renderEnvelopes([l])}}const r=new class extends s{renderEnvelopes(e){(null==e?void 0:e.length)&&this.isDependencyAvailable()&&e.forEach((e=>{try{const{message:s,title:r,type:o,options:i}=e,n=t[o](s,r,i);if(n&&n.parent)try{const e=n.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)}}))}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",r),r}));
|
||||
|
||||
+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
+43
-9
@@ -1,17 +1,51 @@
|
||||
{
|
||||
"/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=2dfca2b3c2159f2ff676a62ad338f092",
|
||||
"/vendor/flasher/flasher.min.css": "/vendor/flasher/flasher.min.css?id=689710919ac658a64bacd98998f04534",
|
||||
"/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=2e8cbc1a93524a122b8f62f072f2ff71",
|
||||
"/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=aeaeda5a1eadd052f0c466fdf6c6f7b3",
|
||||
"/vendor/flasher/themes/google/google.min.js": "/vendor/flasher/themes/google/google.min.js?id=812cddda9e58967cd46fb1f5a385b8ec",
|
||||
"/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=7b56b75dafcf90e2fd3cf243f6e17ede",
|
||||
"/vendor/flasher/themes/flasher/flasher.min.css": "/vendor/flasher/themes/flasher/flasher.min.css?id=a806450943da43e7876dd3ddf78c47bc",
|
||||
"/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=16817691e8c76e7a27ea1be3a9d3e288",
|
||||
"/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=b98d586c16df24f556bd509d128d4206",
|
||||
"/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=1497c70c9875d728c439136c92fbca08",
|
||||
"/vendor/flasher/themes/ios/ios.min.js": "/vendor/flasher/themes/ios/ios.min.js?id=7149c00236bda6f7aecfd7f0ce18a1f4",
|
||||
"/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=2c8dc59c4abefd370535eb102d4e6711",
|
||||
"/vendor/flasher/themes/amber/amber.min.js": "/vendor/flasher/themes/amber/amber.min.js?id=95b57e413d5cb896b47ad9158dd4ef07",
|
||||
"/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=7ce0a41e3886db70a56b6e9e49bdda91",
|
||||
"/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=01987a2d265f63b2e92fe5f3e4b61496",
|
||||
"/vendor/flasher/themes/slack/slack.min.js": "/vendor/flasher/themes/slack/slack.min.js?id=6b1ade06f3eb351e9eaef76d402918fb",
|
||||
"/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=0fbcab9da8649325269c934da21006cc",
|
||||
"/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=0360045692aaa32af12dc9739374fdae",
|
||||
"/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=7c8e19091329bd9242408f8d5b9890e7",
|
||||
"/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=815113a3e5023948b5f700f5d62253dd",
|
||||
"/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=4a788f294fa818764ee4d3e1cf10a330",
|
||||
"/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=d6c390269f18e78bc9c74a98fc6c3c29",
|
||||
"/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=1ba7dae06e6524905228794c1db14290",
|
||||
"/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(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";e.addTheme("amazon",{render:e=>{const{type:n,message:t}=e,r="error"===n||"warning"===n;return`\n <div class="fl-amazon fl-${n}" role="${r?"alert":"status"}" aria-live="${r?"assertive":"polite"}" aria-atomic="true">\n <div class="fl-amazon-alert">\n <div class="fl-alert-content">\n <div class="fl-icon-container">\n ${(()=>{switch(n){case"success":return'<svg viewBox="0 0 24 24" width="24" height="24">\n <path fill="currentColor" d="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"/>\n </svg>';case"error":return'<svg viewBox="0 0 24 24" width="24" height="24">\n <path fill="currentColor" d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z"/>\n </svg>';case"warning":return'<svg viewBox="0 0 24 24" width="24" height="24">\n <path fill="currentColor" d="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z"/>\n </svg>';case"info":return'<svg viewBox="0 0 24 24" width="24" height="24">\n <path fill="currentColor" d="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"/>\n </svg>'}return""})()}\n </div>\n <div class="fl-text-content">\n <div class="fl-alert-title">${(()=>{switch(n){case"success":return"Success!";case"error":return"Problem";case"warning":return"Warning";case"info":return"Information";default:return"Alert"}})()}</div>\n <div class="fl-alert-message">${t}</div>\n </div>\n </div>\n <div class="fl-alert-actions">\n <button class="fl-close" aria-label="Close notification">\n <svg viewBox="0 0 24 24" width="16" height="16">\n <path fill="currentColor" d="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"/>\n </svg>\n </button>\n </div>\n </div>\n </div>`}})}));
|
||||
@@ -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";e.addTheme("amber",{render:e=>{const{type:s,message:i}=e,l="error"===s||"warning"===s;return`\n <div class="fl-amber fl-${s}" role="${l?"alert":"status"}" aria-live="${l?"assertive":"polite"}" aria-atomic="true">\n <div class="fl-content">\n <div class="fl-icon"></div>\n <div class="fl-text">\n <div class="fl-message">${i}</div>\n </div>\n <button class="fl-close" aria-label="Close ${s} message">×</button>\n </div>\n <div class="fl-progress-bar">\n <div class="fl-progress"></div>\n </div>\n </div>`}})}));
|
||||
@@ -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,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";e.addTheme("aurora",{render:e=>{const{type:s,message:a}=e,r="error"===s||"warning"===s;return`\n <div class="fl-aurora fl-${s}" role="${r?"alert":"status"}" aria-live="${r?"assertive":"polite"}" aria-atomic="true">\n <div class="fl-content">\n <div class="fl-message">${a}</div>\n <button class="fl-close" aria-label="Close ${s} message">×</button>\n </div>\n <div class="fl-progress-bar">\n <div class="fl-progress"></div>\n </div>\n </div>`}})}));
|
||||
@@ -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";e.addTheme("crystal",{render:e=>{const{type:s,message:l}=e,a="error"===s||"warning"===s;return`\n <div class="fl-crystal fl-${s}" role="${a?"alert":"status"}" aria-live="${a?"assertive":"polite"}" aria-atomic="true">\n <div class="fl-content">\n <div class="fl-text">\n <p class="fl-message">${l}</p>\n </div>\n <button class="fl-close" aria-label="Close ${s} message">×</button>\n </div>\n <div class="fl-progress-bar">\n <div class="fl-progress"></div>\n </div>\n </div>`}})}));
|
||||
@@ -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,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";e.addTheme("emerald",{render:e=>{const{type:s,message:a}=e,l="error"===s||"warning"===s;return`\n <div class="fl-emerald fl-${s}" role="${l?"alert":"status"}" aria-live="${l?"assertive":"polite"}" aria-atomic="true">\n <div class="fl-content">\n <div class="fl-message">${a}</div>\n <button class="fl-close" aria-label="Close ${s} message">×</button>\n </div>\n </div>`}})}));
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
!function(n,i){"object"==typeof exports&&"undefined"!=typeof module?i(require("@flasher/flasher")):"function"==typeof define&&define.amd?define(["@flasher/flasher"],i):i((n="undefined"!=typeof globalThis?globalThis:n||self).flasher)}(this,(function(n){"use strict";const i={render:n=>{const{type:i,message:e}=n,s="error"===i||"warning"===i,t=s?"alert":"status",l=s?"assertive":"polite",o=(new Date).toLocaleTimeString([],{hour:"numeric",minute:"2-digit"});return`\n <div class="fl-facebook fl-${i}" role="${t}" aria-live="${l}" aria-atomic="true">\n <div class="fl-fb-notification">\n <div class="fl-icon-container">\n ${(()=>{switch(i){case"success":return'<div class="fl-fb-icon fl-fb-icon-success">\n <svg viewBox="0 0 24 24" width="16" height="16">\n <path fill="currentColor" d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm-1-11v6h2v-6h-2zm0-4v2h2V7h-2z"/>\n </svg>\n </div>';case"error":return'<div class="fl-fb-icon fl-fb-icon-error">\n <svg viewBox="0 0 24 24" width="16" height="16">\n <path fill="currentColor" d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm0-11.5c-.69 0-1.25.56-1.25 1.25S11.31 13 12 13s1.25-.56 1.25-1.25S12.69 10.5 12 10.5zM12 9c.552 0 1-.448 1-1V7c0-.552-.448-1-1-1s-1 .448-1 1v1c0 .552.448 1 1 1z"/>\n </svg>\n </div>';case"warning":return'<div class="fl-fb-icon fl-fb-icon-warning">\n <svg viewBox="0 0 24 24" width="16" height="16">\n <path fill="currentColor" d="M12.865 3.00017L22.3912 19.5002C22.6674 19.9785 22.5035 20.5901 22.0252 20.8662C21.8732 20.954 21.7008 21.0002 21.5252 21.0002H2.47266C1.92037 21.0002 1.47266 20.5525 1.47266 20.0002C1.47266 19.8246 1.51886 19.6522 1.60663 19.5002L11.1329 3.00017C11.409 2.52187 12.0206 2.358 12.4989 2.63414C12.651 2.72192 12.7772 2.84815 12.865 3.00017ZM11 16.0002V18.0002H13V16.0002H11ZM11 8.00017V14.0002H13V8.00017H11Z"/>\n </svg>\n </div>';case"info":return'<div class="fl-fb-icon fl-fb-icon-info">\n <svg viewBox="0 0 24 24" width="16" height="16">\n <path fill="currentColor" d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm0-2a8 8 0 100-16 8 8 0 000 16zm-1-5h2v-2h-2v2zm0-4h2V7h-2v4z"/>\n </svg>\n </div>'}return""})()}\n </div>\n <div class="fl-content">\n <div class="fl-message">\n ${e}\n </div>\n <div class="fl-meta">\n <span class="fl-time">${o}</span>\n </div>\n </div>\n <div class="fl-actions">\n <button class="fl-button fl-close" aria-label="Close ${i} message">\n <div class="fl-button-icon">\n <svg viewBox="0 0 24 24" width="20" height="20">\n <path fill="currentColor" d="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 12 19 6.41z"/>\n </svg>\n </div>\n </button>\n </div>\n </div>\n </div>`}};n.addTheme("facebook",i)}));
|
||||
File diff suppressed because one or more lines are too long
@@ -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";e.addTheme("flasher",{render:e=>{const{type:s,title:n,message:a}=e,l="error"===s||"warning"===s,t=l?"alert":"status",r=l?"assertive":"polite",i=n||s.charAt(0).toUpperCase()+s.slice(1);return`\n <div class="fl-flasher fl-${s}" role="${t}" aria-live="${r}" aria-atomic="true">\n <div class="fl-content">\n <div class="fl-icon"></div>\n <div>\n <strong class="fl-title">${i}</strong>\n <span class="fl-message">${a}</span>\n </div>\n <button class="fl-close" aria-label="Close ${s} message">×</button>\n </div>\n <span class="fl-progress-bar">\n <span class="fl-progress"></span>\n </span>\n </div>`}})}));
|
||||
@@ -0,0 +1 @@
|
||||
.fl-google{--md-bg-light:#fff;--md-bg-dark:#2d2d2d;--md-text-light:rgba(0,0,0,.87);--md-text-secondary-light:rgba(0,0,0,.6);--md-text-dark:hsla(0,0%,100%,.87);--md-text-secondary-dark:hsla(0,0%,100%,.6);--md-elevation:0 3px 5px -1px rgba(0,0,0,.2),0 6px 10px 0 rgba(0,0,0,.14),0 1px 18px 0 rgba(0,0,0,.12);--md-elevation-dark:0 3px 5px -1px rgba(0,0,0,.4),0 6px 10px 0 rgba(0,0,0,.28),0 1px 18px 0 rgba(0,0,0,.24);--md-border-radius:4px;--md-success:#43a047;--md-info:#1e88e5;--md-warning:#fb8c00;--md-error:#e53935;--md-animation-duration:0.3s;--md-ripple-duration:0.6s}@keyframes mdSlideUp{0%{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}@keyframes mdRipple{to{opacity:0;transform:scale(4)}}.fl-google{animation:mdSlideUp var(--md-animation-duration) cubic-bezier(.4,0,.2,1);font-family:Roboto,Segoe UI,Helvetica,Arial,sans-serif;margin:8px 0;position:relative}.fl-google .fl-md-card{background-color:var(--md-bg-light);border-radius:var(--md-border-radius);box-shadow:var(--md-elevation);color:var(--md-text-light);overflow:hidden}.fl-google .fl-content{align-items:flex-start;display:flex;padding:16px}.fl-google .fl-icon-wrapper{color:var(--md-text-secondary-light);flex-shrink:0;margin-right:16px}.fl-google .fl-text-content{flex:1}.fl-google .fl-title{font-size:1rem;font-weight:500;margin-bottom:4px}.fl-google .fl-message{color:var(--md-text-secondary-light);font-size:.875rem;line-height:1.43}.fl-google .fl-actions{display:flex;justify-content:flex-end;padding:8px}.fl-google .fl-action-button{background:transparent;border:none;border-radius:4px;color:currentColor;cursor:pointer;font-family:inherit;font-size:.8125rem;font-weight:500;letter-spacing:.0892857143em;overflow:hidden;padding:8px 12px;position:relative;text-transform:uppercase;transition:background-color .2s}.fl-google .fl-action-button:focus,.fl-google .fl-action-button:hover{background-color:rgba(0,0,0,.04)}.fl-google .fl-action-button:after{background:currentColor;border-radius:50%;content:"";height:5px;opacity:0;pointer-events:none;position:absolute;transform:scale(1);width:5px}.fl-google .fl-action-button:active:after{animation:mdRipple var(--md-ripple-duration) linear;opacity:.3}.fl-google.fl-success .fl-action-button,.fl-google.fl-success .fl-icon-wrapper{color:var(--md-success)}.fl-google.fl-info .fl-action-button,.fl-google.fl-info .fl-icon-wrapper{color:var(--md-info)}.fl-google.fl-warning .fl-action-button,.fl-google.fl-warning .fl-icon-wrapper{color:var(--md-warning)}.fl-google.fl-error .fl-action-button,.fl-google.fl-error .fl-icon-wrapper{color:var(--md-error)}.fl-google .fl-progress-bar{bottom:0;height:4px;left:0;overflow:hidden;position:absolute;right:0}.fl-google .fl-progress-bar .fl-progress{height:100%;transform-origin:left center;width:100%}.fl-google.fl-success .fl-progress{background-color:var(--md-success)}.fl-google.fl-info .fl-progress{background-color:var(--md-info)}.fl-google.fl-warning .fl-progress{background-color:var(--md-warning)}.fl-google.fl-error .fl-progress{background-color:var(--md-error)}.fl-google.fl-rtl{direction:rtl}.fl-google.fl-rtl .fl-content{flex-direction:row-reverse}.fl-google.fl-rtl .fl-icon-wrapper{margin-left:16px;margin-right:0}.fl-google.fl-rtl .fl-actions{justify-content:flex-start}.fl-google.fl-rtl .fl-progress{transform-origin:right center}@media (prefers-reduced-motion:reduce){.fl-google,.fl-google .fl-action-button:active:after{animation:none}}.fl-google.fl-auto-dark .fl-md-card,body.fl-dark .fl-google .fl-md-card,html.fl-dark .fl-google .fl-md-card{background-color:var(--md-bg-dark);box-shadow:var(--md-elevation-dark);color:var(--md-text-dark)}.fl-google.fl-auto-dark .fl-message,body.fl-dark .fl-google .fl-message,html.fl-dark .fl-google .fl-message{color:var(--md-text-secondary-dark)}.fl-google.fl-auto-dark .fl-action-button:focus,.fl-google.fl-auto-dark .fl-action-button:hover,body.fl-dark .fl-google .fl-action-button:focus,body.fl-dark .fl-google .fl-action-button:hover,html.fl-dark .fl-google .fl-action-button:focus,html.fl-dark .fl-google .fl-action-button:hover{background-color:hsla(0,0%,100%,.08)}
|
||||
@@ -0,0 +1 @@
|
||||
!function(s,e){"object"==typeof exports&&"undefined"!=typeof module?e(require("@flasher/flasher")):"function"==typeof define&&define.amd?define(["@flasher/flasher"],e):e((s="undefined"!=typeof globalThis?globalThis:s||self).flasher)}(this,(function(s){"use strict";s.addTheme("google",{render:s=>{const{type:e,message:n,title:l}=s,i="error"===e||"warning"===e,t=l?`<div class="fl-title">${l}</div>`:"";return`\n <div class="fl-google fl-${e}" role="${i?"alert":"status"}" aria-live="${i?"assertive":"polite"}" aria-atomic="true">\n <div class="fl-md-card">\n <div class="fl-content">\n <div class="fl-icon-wrapper">\n ${(()=>{switch(e){case"success":return'<svg class="fl-icon-svg" viewBox="0 0 24 24" width="24" height="24">\n <path fill="currentColor" d="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"/>\n </svg>';case"error":return'<svg class="fl-icon-svg" viewBox="0 0 24 24" width="24" height="24">\n <path fill="currentColor" d="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"/>\n </svg>';case"warning":return'<svg class="fl-icon-svg" viewBox="0 0 24 24" width="24" height="24">\n <path fill="currentColor" d="M12 5.99L19.53 19H4.47L12 5.99M12 2L1 21h22L12 2zm1 14h-2v2h2v-2zm0-6h-2v4h2v-4z"/>\n </svg>';case"info":return'<svg class="fl-icon-svg" viewBox="0 0 24 24" width="24" height="24">\n <path fill="currentColor" d="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"/>\n </svg>'}return""})()}\n </div>\n <div class="fl-text-content">\n ${t}\n <div class="fl-message">${n}</div>\n </div>\n </div>\n <div class="fl-actions">\n <button class="fl-action-button fl-close" aria-label="Close ${e} message">\n DISMISS\n </button>\n </div>\n </div>\n <div class="fl-progress-bar">\n <div class="fl-progress"></div>\n </div>\n </div>`}})}));
|
||||
@@ -0,0 +1 @@
|
||||
.fl-ios{--ios-bg-light:#fff;--ios-bg-dark:#1e1e1e;--ios-text-light:#000;--ios-text-secondary-light:#6e6e6e;--ios-text-dark:#fff;--ios-text-secondary-dark:#a8a8a8;--ios-border-radius:13px;--ios-shadow:0 2px 12px rgba(0,0,0,.15);--ios-shadow-dark:0 2px 12px rgba(0,0,0,.35);--ios-icon-size:18px;--ios-blur:30px;--ios-success:#34c759;--ios-info:#007aff;--ios-warning:#ff9500;--ios-error:#ff3b30;--ios-animation-duration:0.4s}@keyframes iosSlideIn{0%{opacity:0;transform:translateY(-15px) scale(.96)}to{opacity:1;transform:translateY(0) scale(1)}}@keyframes iosExpand{0%{max-height:0;opacity:0}to{max-height:100px;opacity:1}}.fl-ios{animation:iosSlideIn var(--ios-animation-duration) cubic-bezier(.23,1,.32,1);font-family:-apple-system,BlinkMacSystemFont,San Francisco,Helvetica Neue,Helvetica,Arial,sans-serif;margin:10px 0;position:relative;will-change:transform,opacity}.fl-ios .fl-ios-notification{backdrop-filter:blur(var(--ios-blur));-webkit-backdrop-filter:blur(var(--ios-blur));background-color:var(--ios-bg-light);border-radius:var(--ios-border-radius);box-shadow:var(--ios-shadow);color:var(--ios-text-light);padding:12px 15px;position:relative}.fl-ios .fl-header{align-items:center;display:flex;margin-bottom:8px;padding-right:20px}.fl-ios .fl-app-icon{align-items:center;background-color:currentColor;border-radius:5px;display:flex;flex-shrink:0;height:22px;justify-content:center;margin-right:8px;width:22px}.fl-ios .fl-icon-svg{color:#fff;height:14px;width:14px}.fl-ios .fl-app-info{align-items:baseline;display:flex;flex:1;justify-content:space-between}.fl-ios .fl-app-name{font-size:.85rem;font-weight:600}.fl-ios .fl-time{color:var(--ios-text-secondary-light);flex-shrink:0;font-size:.75rem;margin-left:5px}.fl-ios .fl-content{animation:iosExpand .3s forwards;animation-delay:.1s;overflow:hidden}.fl-ios .fl-message{font-size:.95rem;line-height:1.3;margin:0;padding-right:15px}.fl-ios .fl-close{align-items:center;background-color:rgba(0,0,0,.1);border:none;border-radius:50%;color:var(--ios-text-light);cursor:pointer;display:flex;font-size:14px;height:18px;justify-content:center;line-height:1;opacity:.7;padding:0;position:absolute;right:12px;top:10px;transition:opacity .2s;width:18px}.fl-ios .fl-close:focus,.fl-ios .fl-close:hover{opacity:1}.fl-ios.fl-success .fl-app-icon{color:var(--ios-success)}.fl-ios.fl-info .fl-app-icon{color:var(--ios-info)}.fl-ios.fl-warning .fl-app-icon{color:var(--ios-warning)}.fl-ios.fl-error .fl-app-icon{color:var(--ios-error)}.fl-ios.fl-rtl{direction:rtl}.fl-ios.fl-rtl .fl-header{padding-left:20px;padding-right:0}.fl-ios.fl-rtl .fl-app-icon{margin-left:8px;margin-right:0}.fl-ios.fl-rtl .fl-time{margin-left:0;margin-right:5px}.fl-ios.fl-rtl .fl-message{padding-left:15px;padding-right:0}.fl-ios.fl-rtl .fl-close{left:12px;right:auto}@media (prefers-reduced-motion:reduce){.fl-ios{animation:none}.fl-ios .fl-content{animation:none;max-height:none;opacity:1}}@media screen and (max-width:480px){.fl-ios{width:100%}}.fl-ios.fl-auto-dark .fl-ios-notification,body.fl-dark .fl-ios .fl-ios-notification,html.fl-dark .fl-ios .fl-ios-notification{background-color:var(--ios-bg-dark);box-shadow:var(--ios-shadow-dark);color:var(--ios-text-dark)}.fl-ios.fl-auto-dark .fl-time,body.fl-dark .fl-ios .fl-time,html.fl-dark .fl-ios .fl-time{color:var(--ios-text-secondary-dark)}.fl-ios.fl-auto-dark .fl-close,body.fl-dark .fl-ios .fl-close,html.fl-dark .fl-ios .fl-close{background-color:hsla(0,0%,100%,.2);color:var(--ios-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={render:e=>{const{type:s,message:i,title:n}=e,l="error"===s||"warning"===s,t=l?"alert":"status",a=l?"assertive":"polite",r=(new Date).toLocaleTimeString([],{hour:"numeric",minute:"2-digit"}),o=n||"PHPFlasher";return`\n <div class="fl-ios fl-${s}" role="${t}" aria-live="${a}" aria-atomic="true">\n <div class="fl-ios-notification">\n <div class="fl-header">\n <div class="fl-app-icon">\n ${(()=>{switch(s){case"success":return'<svg class="fl-icon-svg" viewBox="0 0 24 24" width="20" height="20">\n <path fill="currentColor" d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/>\n </svg>';case"error":return'<svg class="fl-icon-svg" viewBox="0 0 24 24" width="20" height="20">\n <path fill="currentColor" d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z"/>\n </svg>';case"warning":return'<svg class="fl-icon-svg" viewBox="0 0 24 24" width="20" height="20">\n <path fill="currentColor" d="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z"/>\n </svg>';case"info":return'<svg class="fl-icon-svg" viewBox="0 0 24 24" width="20" height="20">\n <path fill="currentColor" d="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"/>\n </svg>'}return""})()}\n </div>\n <div class="fl-app-info">\n <div class="fl-app-name">${o}</div>\n <div class="fl-time">${r}</div>\n </div>\n </div>\n <div class="fl-content">\n <div class="fl-message">${i}</div>\n </div>\n <button class="fl-close" aria-label="Close ${s} message">\n <span aria-hidden="true">×</span>\n </button>\n </div>\n </div>`}};e.addTheme("ios",s)}));
|
||||
@@ -0,0 +1 @@
|
||||
.fl-jade{--jade-text-light:#5f6c7b;--jade-text-dark:#e2e8f0;--jade-shadow:0 8px 24px hsla(210,8%,62%,.1);--jade-shadow-dark:0 8px 24px rgba(0,0,0,.2);--jade-border-radius:4px;--jade-transition:0.3s cubic-bezier(0.4,0,0.2,1);--jade-success-bg:#f0fdf4;--jade-success-color:#16a34a;--jade-info-bg:#eff6ff;--jade-info-color:#3b82f6;--jade-warning-bg:#fffbeb;--jade-warning-color:#f59e0b;--jade-error-bg:#fef2f2;--jade-error-color:#dc2626;--jade-success-bg-dark:rgba(22,163,74,.15);--jade-info-bg-dark:rgba(59,130,246,.15);--jade-warning-bg-dark:rgba(245,158,11,.15);--jade-error-bg-dark:rgba(220,38,38,.15)}@keyframes jadeIn{0%{opacity:0;transform:translateY(-10px) scale(.95)}to{opacity:1;transform:translateY(0) scale(1)}}.fl-jade{animation:jadeIn .4s var(--jade-transition);border:1px solid transparent;border-radius:var(--jade-border-radius) var(--jade-border-radius) 0 0;box-shadow:var(--jade-shadow);font-family:var(--fl-font),serif;margin:.5rem 0;overflow:hidden;padding:1rem 1.25rem;position:relative;will-change:transform,opacity}.fl-jade .fl-content{align-items:center;display:flex}.fl-jade .fl-message{flex:1;font-size:.875rem;font-weight:500;line-height:1.5;padding-right:.75rem}.fl-jade .fl-close{align-items:center;background:none;border:none;border-radius:50%;cursor:pointer;display:flex;flex-shrink:0;font-size:1.125rem;height:1.875rem;justify-content:center;opacity:.6;padding:.375rem;transition:all var(--jade-transition);width:1.875rem}.fl-jade .fl-close:focus,.fl-jade .fl-close:hover{background-color:rgba(0,0,0,.05);opacity:1}.fl-jade .fl-progress-bar{border-radius:0 0 var(--jade-border-radius) var(--jade-border-radius);bottom:0;height:3px;left:0;opacity:.7;overflow:hidden;position:absolute;right:0}.fl-jade .fl-progress-bar .fl-progress{height:100%;width:100%}.fl-jade.fl-success{background-color:var(--jade-success-bg);border-color:rgba(22,163,74,.1)}.fl-jade.fl-success,.fl-jade.fl-success .fl-close{color:var(--jade-success-color)}.fl-jade.fl-success .fl-close:focus,.fl-jade.fl-success .fl-close:hover{background-color:rgba(22,163,74,.1)}.fl-jade.fl-success .fl-progress-bar .fl-progress{background-color:var(--jade-success-color)}.fl-jade.fl-info{background-color:var(--jade-info-bg);border-color:rgba(59,130,246,.1)}.fl-jade.fl-info,.fl-jade.fl-info .fl-close{color:var(--jade-info-color)}.fl-jade.fl-info .fl-close:focus,.fl-jade.fl-info .fl-close:hover{background-color:rgba(59,130,246,.1)}.fl-jade.fl-info .fl-progress-bar .fl-progress{background-color:var(--jade-info-color)}.fl-jade.fl-warning{background-color:var(--jade-warning-bg);border-color:rgba(245,158,11,.1)}.fl-jade.fl-warning,.fl-jade.fl-warning .fl-close{color:var(--jade-warning-color)}.fl-jade.fl-warning .fl-close:focus,.fl-jade.fl-warning .fl-close:hover{background-color:rgba(245,158,11,.1)}.fl-jade.fl-warning .fl-progress-bar .fl-progress{background-color:var(--jade-warning-color)}.fl-jade.fl-error{background-color:var(--jade-error-bg);border-color:rgba(220,38,38,.1)}.fl-jade.fl-error,.fl-jade.fl-error .fl-close{color:var(--jade-error-color)}.fl-jade.fl-error .fl-close:focus,.fl-jade.fl-error .fl-close:hover{background-color:rgba(220,38,38,.1)}.fl-jade.fl-error .fl-progress-bar .fl-progress{background-color:var(--jade-error-color)}.fl-jade.fl-rtl{direction:rtl}.fl-jade.fl-rtl .fl-message{padding-left:.75rem;padding-right:0}.fl-jade.fl-rtl .fl-progress .fl-progress{transform-origin:right center}@media (prefers-reduced-motion:reduce){.fl-jade{animation:none}}.fl-jade.fl-auto-dark,body.fl-dark .fl-jade,html.fl-dark .fl-jade{box-shadow:var(--jade-shadow-dark);color:var(--jade-text-dark)}.fl-jade.fl-auto-dark.fl-success,body.fl-dark .fl-jade.fl-success,html.fl-dark .fl-jade.fl-success{background-color:var(--jade-success-bg-dark);border-color:rgba(22,163,74,.2)}.fl-jade.fl-auto-dark.fl-info,body.fl-dark .fl-jade.fl-info,html.fl-dark .fl-jade.fl-info{background-color:var(--jade-info-bg-dark);border-color:rgba(59,130,246,.2)}.fl-jade.fl-auto-dark.fl-warning,body.fl-dark .fl-jade.fl-warning,html.fl-dark .fl-jade.fl-warning{background-color:var(--jade-warning-bg-dark);border-color:rgba(245,158,11,.2)}.fl-jade.fl-auto-dark.fl-error,body.fl-dark .fl-jade.fl-error,html.fl-dark .fl-jade.fl-error{background-color:var(--jade-error-bg-dark);border-color:rgba(220,38,38,.2)}.fl-jade.fl-auto-dark .fl-close:focus,.fl-jade.fl-auto-dark .fl-close:hover,body.fl-dark .fl-jade .fl-close:focus,body.fl-dark .fl-jade .fl-close:hover,html.fl-dark .fl-jade .fl-close:focus,html.fl-dark .fl-jade .fl-close:hover{background-color:hsla(0,0%,100%,.1)}
|
||||
@@ -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";e.addTheme("jade",{render:e=>{const{type:s,message:a}=e,l="error"===s||"warning"===s;return`\n <div class="fl-jade fl-${s}" role="${l?"alert":"status"}" aria-live="${l?"assertive":"polite"}" aria-atomic="true">\n <div class="fl-content">\n <div class="fl-message">${a}</div>\n <button class="fl-close" aria-label="Close ${s} message">×</button>\n </div>\n <div class="fl-progress-bar">\n <div class="fl-progress"></div>\n </div>\n </div>`}})}));
|
||||
@@ -0,0 +1 @@
|
||||
.fl-material{--md-bg-light:#fff;--md-bg-dark:#2d2d2d;--md-text-light:rgba(0,0,0,.87);--md-text-secondary-light:rgba(0,0,0,.6);--md-text-dark:hsla(0,0%,100%,.87);--md-text-secondary-dark:hsla(0,0%,100%,.6);--md-elevation:0 3px 5px -1px rgba(0,0,0,.2),0 6px 10px 0 rgba(0,0,0,.14),0 1px 18px 0 rgba(0,0,0,.12);--md-elevation-dark:0 3px 5px -1px rgba(0,0,0,.4),0 6px 10px 0 rgba(0,0,0,.28),0 1px 18px 0 rgba(0,0,0,.24);--md-border-radius:4px;--md-success:#43a047;--md-info:#1e88e5;--md-warning:#fb8c00;--md-error:#e53935;--md-animation-duration:0.3s;--md-ripple-duration:0.6s}@keyframes mdSlideUp{0%{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}@keyframes mdRipple{to{opacity:0;transform:scale(4)}}.fl-material{animation:mdSlideUp var(--md-animation-duration) cubic-bezier(.4,0,.2,1);font-family:Roboto,Segoe UI,Helvetica,Arial,sans-serif;margin:8px 0;position:relative}.fl-material .fl-md-card{background-color:var(--md-bg-light);border-radius:var(--md-border-radius);box-shadow:var(--md-elevation);color:var(--md-text-light);overflow:hidden}.fl-material .fl-content{align-items:flex-start;display:flex;padding:16px}.fl-material .fl-text-content{flex:1}.fl-material .fl-message{color:var(--md-text-secondary-light);font-size:.875rem;line-height:1.43}.fl-material .fl-actions{display:flex;justify-content:flex-end;padding:8px}.fl-material .fl-action-button{background:transparent;border:none;border-radius:4px;color:currentColor;cursor:pointer;font-family:inherit;font-size:.8125rem;font-weight:500;letter-spacing:.0892857143em;overflow:hidden;padding:8px 12px;position:relative;text-transform:uppercase;transition:background-color .2s}.fl-material .fl-action-button:focus,.fl-material .fl-action-button:hover{background-color:rgba(0,0,0,.04)}.fl-material .fl-action-button:after{background:currentColor;border-radius:50%;content:"";height:5px;opacity:0;pointer-events:none;position:absolute;transform:scale(1);width:5px}.fl-material .fl-action-button:active:after{animation:mdRipple var(--md-ripple-duration) linear;opacity:.3}.fl-material.fl-success .fl-action-button,.fl-material.fl-success .fl-icon-wrapper{color:var(--md-success)}.fl-material.fl-info .fl-action-button,.fl-material.fl-info .fl-icon-wrapper{color:var(--md-info)}.fl-material.fl-warning .fl-action-button,.fl-material.fl-warning .fl-icon-wrapper{color:var(--md-warning)}.fl-material.fl-error .fl-action-button,.fl-material.fl-error .fl-icon-wrapper{color:var(--md-error)}.fl-material .fl-progress-bar{bottom:0;height:4px;left:0;overflow:hidden;position:absolute;right:0}.fl-material .fl-progress-bar .fl-progress{height:100%;transform-origin:left center;width:100%}.fl-material.fl-success .fl-progress{background-color:var(--md-success)}.fl-material.fl-info .fl-progress{background-color:var(--md-info)}.fl-material.fl-warning .fl-progress{background-color:var(--md-warning)}.fl-material.fl-error .fl-progress{background-color:var(--md-error)}.fl-material.fl-rtl{direction:rtl}.fl-material.fl-rtl .fl-content{flex-direction:row-reverse}.fl-material.fl-rtl .fl-icon-wrapper{margin-left:16px;margin-right:0}.fl-material.fl-rtl .fl-actions{justify-content:flex-start}.fl-material.fl-rtl .fl-progress{transform-origin:right center}@media (prefers-reduced-motion:reduce){.fl-material,.fl-material .fl-action-button:active:after{animation:none}}.fl-material.fl-auto-dark .fl-md-card,body.fl-dark .fl-material .fl-md-card,html.fl-dark .fl-material .fl-md-card{background-color:var(--md-bg-dark);box-shadow:var(--md-elevation-dark);color:var(--md-text-dark)}.fl-material.fl-auto-dark .fl-message,body.fl-dark .fl-material .fl-message,html.fl-dark .fl-material .fl-message{color:var(--md-text-secondary-dark)}.fl-material.fl-auto-dark .fl-action-button:focus,.fl-material.fl-auto-dark .fl-action-button:hover,body.fl-dark .fl-material .fl-action-button:focus,body.fl-dark .fl-material .fl-action-button:hover,html.fl-dark .fl-material .fl-action-button:focus,html.fl-dark .fl-material .fl-action-button:hover{background-color:hsla(0,0%,100%,.08)}
|
||||
@@ -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";e.addTheme("material",{render:e=>{const{type:s,message:n}=e,a="error"===s||"warning"===s;return`\n <div class="fl-material fl-${s}" role="${a?"alert":"status"}" aria-live="${a?"assertive":"polite"}" aria-atomic="true">\n <div class="fl-md-card">\n <div class="fl-content">\n <div class="fl-text-content">\n <div class="fl-message">${n}</div>\n </div>\n </div>\n <div class="fl-actions">\n <button class="fl-action-button fl-close" aria-label="Close ${s} message">\n DISMISS\n </button>\n </div>\n </div>\n <div class="fl-progress-bar">\n <div class="fl-progress"></div>\n </div>\n </div>`}})}));
|
||||
@@ -0,0 +1 @@
|
||||
.fl-minimal{--minimal-bg-light:#fff;--minimal-bg-dark:#191919;--minimal-text-light:#333;--minimal-text-dark:#f5f5f5;--minimal-shadow:0 2px 8px rgba(0,0,0,.08);--minimal-shadow-dark:0 2px 8px rgba(0,0,0,.15);--minimal-border-radius:4px;--minimal-border-color:rgba(0,0,0,.05);--minimal-border-color-dark:hsla(0,0%,100%,.1);--minimal-success:rgba(34,197,94,.9);--minimal-info:rgba(14,165,233,.9);--minimal-warning:rgba(245,158,11,.9);--minimal-error:rgba(239,68,68,.9)}@keyframes minimalIn{0%{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:translateY(0)}}.fl-minimal{animation:minimalIn .2s ease-out;backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);background-color:var(--minimal-bg-light);border:1px solid var(--minimal-border-color);border-radius:var(--minimal-border-radius);box-shadow:var(--minimal-shadow);color:var(--minimal-text-light);font-family:-apple-system,BlinkMacSystemFont,var(--fl-font),sans-serif;margin:.5rem 0;padding:.75rem 1rem;position:relative;will-change:transform,opacity}.fl-minimal .fl-content{align-items:center;display:flex;gap:.75rem}.fl-minimal .fl-dot{border-radius:50%;flex-shrink:0;height:8px;width:8px}.fl-minimal .fl-message{flex:1;font-size:.875rem;font-weight:450;line-height:1.4;margin:0}.fl-minimal .fl-close{align-items:center;background:none;border:none;color:currentColor;cursor:pointer;display:flex;flex-shrink:0;font-size:1rem;height:1.5rem;justify-content:center;opacity:.5;padding:.25rem;transition:opacity .15s;width:1.5rem}.fl-minimal .fl-close:focus,.fl-minimal .fl-close:hover{opacity:.8}.fl-minimal .fl-progress-bar{border-radius:0 0 var(--minimal-border-radius) var(--minimal-border-radius);bottom:0;height:2px;left:0;opacity:.7;overflow:hidden;position:absolute;right:0}.fl-minimal .fl-progress-bar .fl-progress{height:100%;width:100%}.fl-minimal.fl-success .fl-dot,.fl-minimal.fl-success .fl-progress-bar .fl-progress{background-color:var(--minimal-success)}.fl-minimal.fl-info .fl-dot,.fl-minimal.fl-info .fl-progress-bar .fl-progress{background-color:var(--minimal-info)}.fl-minimal.fl-warning .fl-dot,.fl-minimal.fl-warning .fl-progress-bar .fl-progress{background-color:var(--minimal-warning)}.fl-minimal.fl-error .fl-dot,.fl-minimal.fl-error .fl-progress-bar .fl-progress{background-color:var(--minimal-error)}.fl-minimal.fl-rtl{direction:rtl}.fl-minimal.fl-rtl .fl-progress .fl-progress{transform-origin:right center}@media (prefers-reduced-motion:reduce){.fl-minimal{animation:none}}.fl-minimal.fl-auto-dark,body.fl-dark .fl-minimal,html.fl-dark .fl-minimal{background-color:var(--minimal-bg-dark);border-color:var(--minimal-border-color-dark);box-shadow:var(--minimal-shadow-dark);color:var(--minimal-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";e.addTheme("minimal",{render:e=>{const{type:s,message:i}=e,l="error"===s||"warning"===s;return`\n <div class="fl-minimal fl-${s}" role="${l?"alert":"status"}" aria-live="${l?"assertive":"polite"}" aria-atomic="true">\n <div class="fl-content">\n <div class="fl-message">${i}</div>\n <button class="fl-close" aria-label="Close ${s} message">×</button>\n </div>\n <div class="fl-progress-bar">\n <div class="fl-progress"></div>\n </div>\n </div>`}})}));
|
||||
@@ -0,0 +1 @@
|
||||
.fl-neon{--neon-bg-light:#fff;--neon-bg-dark:#0f172a;--neon-text-light:#334155;--neon-text-dark:#f1f5f9;--neon-shadow:0 8px 30px rgba(0,0,0,.12);--neon-shadow-dark:0 8px 30px rgba(0,0,0,.25);--neon-border-radius:4px;--neon-success:#10b981;--neon-info:#3b82f6;--neon-warning:#f59e0b;--neon-error:#ef4444;--neon-glow-strength:10px;--neon-animation-duration:0.35s}@keyframes neonEntrance{0%{filter:blur(3px);opacity:0;transform:translateY(-15px)}to{filter:blur(0);opacity:1;transform:translateY(0)}}@keyframes neonGlow{0%,to{filter:drop-shadow(0 0 var(--neon-glow-strength) currentColor)}50%{filter:drop-shadow(0 0 calc(var(--neon-glow-strength)*.7) currentColor)}}.fl-neon{animation:neonEntrance var(--neon-animation-duration) ease-out;backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);background-color:var(--neon-bg-light);border-radius:var(--neon-border-radius) var(--neon-border-radius) 0 0;box-shadow:var(--neon-shadow);color:var(--neon-text-light);font-family:"Inter",var(--fl-font),sans-serif;margin:12px 0;overflow:hidden;padding:14px 18px;position:relative;will-change:transform,opacity,filter}.fl-neon .fl-icon-box{align-items:center;animation:neonGlow 3s ease-in-out infinite;border-radius:50%;display:flex;height:24px;justify-content:center;left:16px;position:absolute;top:-12px;width:24px}.fl-neon .fl-icon-box:before{border-radius:50%;content:"";height:100%;opacity:.4;position:absolute;width:100%}.fl-neon .fl-icon-box:after{border-radius:50%;content:"";height:10px;position:relative;width:10px;z-index:1}.fl-neon .fl-content{align-items:center;display:flex}.fl-neon .fl-message{flex:1;font-size:.9375rem;font-weight:500;line-height:1.5}.fl-neon .fl-close{align-items:center;background:none;border:none;border-radius:50%;color:inherit;cursor:pointer;display:flex;flex-shrink:0;font-size:1.2rem;height:28px;justify-content:center;margin-left:16px;opacity:.6;padding:0;transition:all .2s ease;width:28px}.fl-neon .fl-close:focus,.fl-neon .fl-close:hover{background-color:rgba(0,0,0,.06);opacity:1}.fl-neon .fl-progress-bar{border-radius:0 0 var(--neon-border-radius) var(--neon-border-radius);bottom:0;height:3px;left:0;overflow:hidden;position:absolute;right:0}.fl-neon .fl-progress-bar .fl-progress{height:100%;width:100%}.fl-neon.fl-success .fl-icon-box{color:var(--neon-success)}.fl-neon.fl-success .fl-icon-box:after,.fl-neon.fl-success .fl-icon-box:before,.fl-neon.fl-success .fl-progress{background-color:var(--neon-success)}.fl-neon.fl-info .fl-icon-box{color:var(--neon-info)}.fl-neon.fl-info .fl-icon-box:after,.fl-neon.fl-info .fl-icon-box:before,.fl-neon.fl-info .fl-progress{background-color:var(--neon-info)}.fl-neon.fl-warning .fl-icon-box{color:var(--neon-warning)}.fl-neon.fl-warning .fl-icon-box:after,.fl-neon.fl-warning .fl-icon-box:before,.fl-neon.fl-warning .fl-progress{background-color:var(--neon-warning)}.fl-neon.fl-error .fl-icon-box{color:var(--neon-error)}.fl-neon.fl-error .fl-icon-box:after,.fl-neon.fl-error .fl-icon-box:before,.fl-neon.fl-error .fl-progress{background-color:var(--neon-error)}.fl-neon.fl-rtl{direction:rtl}.fl-neon.fl-rtl .fl-icon-box{left:auto;right:16px}.fl-neon.fl-rtl .fl-close{margin-left:0;margin-right:16px}.fl-neon.fl-rtl .fl-progress{transform-origin:right center}@media (prefers-reduced-motion:reduce){.fl-neon,.fl-neon .fl-icon-box{animation:none}}.fl-neon.fl-auto-dark,body.fl-dark .fl-neon,html.fl-dark .fl-neon{background-color:var(--neon-bg-dark);box-shadow:var(--neon-shadow-dark);color:var(--neon-text-dark)}.fl-neon.fl-auto-dark .fl-close:focus,.fl-neon.fl-auto-dark .fl-close:hover,body.fl-dark .fl-neon .fl-close:focus,body.fl-dark .fl-neon .fl-close:hover,html.fl-dark .fl-neon .fl-close:focus,html.fl-dark .fl-neon .fl-close:hover{background-color:hsla(0,0%,100%,.1)}
|
||||
@@ -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";e.addTheme("neon",{render:e=>{const{type:s,message:n}=e,l="error"===s||"warning"===s;return`\n <div class="fl-neon fl-${s}" role="${l?"alert":"status"}" aria-live="${l?"assertive":"polite"}" aria-atomic="true">\n <div class="fl-content">\n <div class="fl-message">${n}</div>\n <button class="fl-close" aria-label="Close ${s} message">×</button>\n </div>\n <div class="fl-progress-bar">\n <div class="fl-progress"></div>\n </div>\n </div>`}})}));
|
||||
@@ -0,0 +1 @@
|
||||
.fl-onyx{--onyx-bg-light:#fff;--onyx-bg-dark:#1e1e1e;--onyx-text-light:#333;--onyx-text-dark:#f5f5f5;--onyx-shadow:0 8px 30px rgba(0,0,0,.12);--onyx-shadow-dark:0 8px 30px rgba(0,0,0,.25);--onyx-border-radius:4px;--onyx-success:#10b981;--onyx-info:#3b82f6;--onyx-warning:#f59e0b;--onyx-error:#ef4444}@keyframes onyxIn{0%{filter:blur(3px);opacity:0;transform:translateY(15px)}to{filter:blur(0);opacity:1;transform:translateY(0)}}.fl-onyx{animation:onyxIn .4s cubic-bezier(.16,1,.3,1);background-color:var(--onyx-bg-light);border-radius:var(--onyx-border-radius) var(--onyx-border-radius) 0 0;box-shadow:var(--onyx-shadow);color:var(--onyx-text-light);font-family:var(--fl-font),serif;margin:.75rem 0;overflow:hidden;padding:1rem 1.25rem;position:relative;will-change:transform,opacity,filter}.fl-onyx:after,.fl-onyx:before{border-radius:50%;content:"";height:6px;position:absolute;width:6px;z-index:1}.fl-onyx:before{left:10px;top:10px}.fl-onyx:after{bottom:10px;right:10px}.fl-onyx .fl-content{align-items:center;display:flex;padding-left:.4rem}.fl-onyx .fl-text{flex:1;position:relative}.fl-onyx .fl-message{font-size:.925rem;font-weight:400;letter-spacing:.01rem;line-height:1.5}.fl-onyx .fl-close{align-items:center;background:none;border:none;border-radius:50%;color:currentColor;cursor:pointer;display:flex;flex-shrink:0;font-size:1.25rem;height:1.75rem;justify-content:center;margin-left:1rem;opacity:.6;padding:.25rem;transition:all .2s ease;width:1.75rem}.fl-onyx .fl-close:focus,.fl-onyx .fl-close:hover{background-color:rgba(0,0,0,.05);opacity:1}.fl-onyx .fl-progress-bar{bottom:0;height:3px;left:0;overflow:hidden;position:absolute;right:0}.fl-onyx .fl-progress-bar .fl-progress{height:100%;transform-origin:left center;width:100%}.fl-onyx.fl-success .fl-progress-bar .fl-progress,.fl-onyx.fl-success:after,.fl-onyx.fl-success:before{background-color:var(--onyx-success)}.fl-onyx.fl-info .fl-progress-bar .fl-progress,.fl-onyx.fl-info:after,.fl-onyx.fl-info:before{background-color:var(--onyx-info)}.fl-onyx.fl-warning .fl-progress-bar .fl-progress,.fl-onyx.fl-warning:after,.fl-onyx.fl-warning:before{background-color:var(--onyx-warning)}.fl-onyx.fl-error .fl-progress-bar .fl-progress,.fl-onyx.fl-error:after,.fl-onyx.fl-error:before{background-color:var(--onyx-error)}.fl-onyx.fl-rtl{direction:rtl}.fl-onyx.fl-rtl .fl-content{padding-left:0;padding-right:.4rem}.fl-onyx.fl-rtl .fl-close{margin-left:0;margin-right:1rem}.fl-onyx.fl-rtl:before{left:auto;right:10px}.fl-onyx.fl-rtl:after{left:10px;right:auto}.fl-onyx.fl-rtl .fl-progress .fl-progress{transform-origin:right center}@media (prefers-reduced-motion:reduce){.fl-onyx{animation:none}}.fl-onyx.fl-auto-dark,body.fl-dark .fl-onyx,html.fl-dark .fl-onyx{background-color:var(--onyx-bg-dark);box-shadow:var(--onyx-shadow-dark);color:var(--onyx-text-dark)}.fl-onyx.fl-auto-dark .fl-close:focus,.fl-onyx.fl-auto-dark .fl-close:hover,body.fl-dark .fl-onyx .fl-close:focus,body.fl-dark .fl-onyx .fl-close:hover,html.fl-dark .fl-onyx .fl-close:focus,html.fl-dark .fl-onyx .fl-close:hover{background-color:hsla(0,0%,100%,.1)}
|
||||
@@ -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";e.addTheme("onyx",{render:e=>{const{type:s,message:n}=e,l="error"===s||"warning"===s;return`\n <div class="fl-onyx fl-${s}" role="${l?"alert":"status"}" aria-live="${l?"assertive":"polite"}" aria-atomic="true">\n <div class="fl-content">\n <div class="fl-text">\n <div class="fl-message">${n}</div>\n </div>\n <button class="fl-close" aria-label="Close ${s} message">×</button>\n </div>\n <div class="fl-progress-bar">\n <div class="fl-progress"></div>\n </div>\n </div>`}})}));
|
||||
@@ -0,0 +1 @@
|
||||
.fl-ruby{--ruby-text:#fff;--ruby-text-dark:#f8fafc;--ruby-border-radius:4px;--ruby-shadow:0 10px 25px -3px rgba(0,0,0,.2);--ruby-success-gradient:linear-gradient(135deg,#059669,#10b981);--ruby-info-gradient:linear-gradient(135deg,#2563eb,#3b82f6);--ruby-warning-gradient:linear-gradient(135deg,#d97706,#f59e0b);--ruby-error-gradient:linear-gradient(135deg,#b91c1c,#ef4444)}@keyframes rubyShine{0%{left:-100%;opacity:.6}60%{left:100%;opacity:.6}to{left:100%;opacity:0}}@keyframes rubyIn{0%{opacity:0;transform:scale(.96)}to{opacity:1;transform:scale(1)}}.fl-ruby{animation:rubyIn .35s cubic-bezier(.21,1.02,.73,1);border-radius:var(--ruby-border-radius) var(--ruby-border-radius) 0 0;box-shadow:var(--ruby-shadow);color:var(--ruby-text);font-family:var(--fl-font),serif;margin:.75rem 0;overflow:hidden;padding:0;position:relative;will-change:transform,opacity}.fl-ruby .fl-shine{animation:rubyShine 6s infinite;animation-delay:1s;background:linear-gradient(90deg,hsla(0,0%,100%,0),hsla(0,0%,100%,.3) 50%,hsla(0,0%,100%,0));height:100%;left:-100%;position:absolute;top:0;transform:skewX(-20deg);width:50%;z-index:1}.fl-ruby .fl-content{align-items:center;display:flex;padding:.9rem 1.1rem;position:relative;z-index:2}.fl-ruby .fl-icon-circle{align-items:center;background-color:hsla(0,0%,100%,.25);border-radius:50%;display:flex;flex-shrink:0;height:2.25rem;justify-content:center;margin-right:1rem;width:2.25rem}.fl-ruby .fl-icon{background-color:transparent;color:var(--ruby-text);font-size:1rem;margin:0}.fl-ruby .fl-text{flex:1}.fl-ruby .fl-message{font-size:.925rem;font-weight:500;line-height:1.5}.fl-ruby .fl-close{align-items:center;background:hsla(0,0%,100%,.2);border:none;border-radius:50%;color:var(--ruby-text);cursor:pointer;display:flex;flex-shrink:0;font-size:1.1rem;height:1.6rem;justify-content:center;margin-left:.75rem;opacity:.8;padding:.1rem;transition:all .2s;width:1.6rem}.fl-ruby .fl-close:focus,.fl-ruby .fl-close:hover{background:hsla(0,0%,100%,.3);opacity:1;transform:scale(1.05)}.fl-ruby .fl-progress-bar{background-color:rgba(0,0,0,.1);bottom:0;height:5px;left:0;overflow:hidden;position:absolute;right:0;z-index:3}.fl-ruby .fl-progress-bar .fl-progress{background:hsla(0,0%,100%,.4);height:100%;width:100%}.fl-ruby.fl-success{background:var(--ruby-success-gradient)}.fl-ruby.fl-info{background:var(--ruby-info-gradient)}.fl-ruby.fl-warning{background:var(--ruby-warning-gradient)}.fl-ruby.fl-error{background:var(--ruby-error-gradient)}.fl-ruby.fl-rtl{direction:rtl}.fl-ruby.fl-rtl .fl-icon-circle{margin-left:1rem;margin-right:0}.fl-ruby.fl-rtl .fl-close{margin-left:0;margin-right:.75rem}.fl-ruby.fl-rtl .fl-shine{transform:skewX(20deg)}.fl-ruby.fl-rtl .fl-progress .fl-progress{transform-origin:right center}@media (prefers-reduced-motion:reduce){.fl-ruby{animation:none}.fl-ruby .fl-shine{display:none}}
|
||||
@@ -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";e.addTheme("ruby",{render:e=>{const{type:s,message:i}=e,l="error"===s||"warning"===s;return`\n <div class="fl-ruby fl-${s}" role="${l?"alert":"status"}" aria-live="${l?"assertive":"polite"}" aria-atomic="true">\n <div class="fl-shine"></div>\n <div class="fl-content">\n <div class="fl-icon-circle">\n <div class="fl-icon"></div>\n </div>\n <div class="fl-text">\n <div class="fl-message">${i}</div>\n </div>\n <button class="fl-close" aria-label="Close ${s} message">×</button>\n </div>\n <div class="fl-progress-bar">\n <div class="fl-progress"></div>\n </div>\n </div>`}})}));
|
||||
@@ -0,0 +1 @@
|
||||
.fl-sapphire{--sapphire-bg-base:rgba(30,30,30,.9);--sapphire-text:#f0f0f0;--sapphire-shadow:rgba(0,0,0,.15);--sapphire-progress-bg:hsla(0,0%,100%,.2);--sapphire-progress-fill:hsla(0,0%,100%,.9);--sapphire-success:rgba(16,185,129,.95);--sapphire-error:rgba(239,68,68,.95);--sapphire-warning:rgba(245,158,11,.95);--sapphire-info:rgba(59,130,246,.95);--sapphire-animation:0.4s cubic-bezier(0.25,0.46,0.45,0.94)}@keyframes sapphireIn{0%{opacity:0;transform:translateY(10px)}60%{transform:translateY(-3px)}to{opacity:1;transform:translateY(0)}}.fl-sapphire{animation:sapphireIn var(--sapphire-animation);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);background-color:var(--sapphire-bg-base);border-radius:4px 4px 0 0;box-shadow:0 6px 16px var(--sapphire-shadow);color:var(--sapphire-text);font-family:Roboto,var(--fl-font),serif;margin:0 0 .75em;padding:1em 1.5em;position:relative;transition:all .3s ease;will-change:transform,opacity}.fl-sapphire .fl-message{color:var(--sapphire-text);font-size:.925em;line-height:1.4}.fl-sapphire .fl-progress-bar{background-color:var(--sapphire-progress-bg);border-radius:0 0 .375em .375em;bottom:0;height:4px;left:0;overflow:hidden;position:absolute;right:0}.fl-sapphire .fl-progress-bar .fl-progress{background-color:var(--sapphire-progress-fill);height:100%;transform-origin:left center;width:100%;will-change:transform}.fl-sapphire.fl-success{background-color:var(--sapphire-success)}.fl-sapphire.fl-error{background-color:var(--sapphire-error)}.fl-sapphire.fl-warning{background-color:var(--sapphire-warning)}.fl-sapphire.fl-info{background-color:var(--sapphire-info)}.fl-sapphire.fl-rtl{direction:rtl}.fl-sapphire.fl-rtl .fl-progress .fl-progress{transform-origin:right center}@media (prefers-reduced-motion:reduce){.fl-sapphire{animation:none}}
|
||||
@@ -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";e.addTheme("sapphire",{render:e=>{const{type:s,message:a}=e,i="error"===s||"warning"===s;return`\n <div class="fl-sapphire fl-${s}" role="${i?"alert":"status"}" aria-live="${i?"assertive":"polite"}" aria-atomic="true">\n <div class="fl-content">\n <span class="fl-message">${a}</span>\n </div>\n <div class="fl-progress-bar">\n <div class="fl-progress"></div>\n </div>\n </div>`}})}));
|
||||
@@ -0,0 +1 @@
|
||||
.fl-slack{--slack-bg-light:#fff;--slack-bg-dark:#1a1d21;--slack-hover-light:#f8f8f8;--slack-hover-dark:#222529;--slack-text-light:#1d1c1d;--slack-text-secondary-light:#616061;--slack-text-dark:#e0e0e0;--slack-text-secondary-dark:#ababad;--slack-border-light:#e0e0e0;--slack-border-dark:#393a3e;--slack-shadow:0 1px 0 rgba(0,0,0,.1);--slack-shadow-dark:0 1px 0 rgba(0,0,0,.2);--slack-avatar-size:36px;--slack-success:#2bac76;--slack-info:#1264a3;--slack-warning:#e8912d;--slack-error:#e01e5a;--slack-animation-duration:150ms}@keyframes slackFadeIn{0%{opacity:0}to{opacity:1}}.fl-slack{animation:slackFadeIn var(--slack-animation-duration) ease-out;font-family:Lato,Slack-Lato,Helvetica Neue,Helvetica,sans-serif;margin:4px 0;position:relative}.fl-slack .fl-slack-message{align-items:flex-start;background-color:var(--slack-bg-light);border:1px solid var(--slack-border-light);border-radius:4px;box-shadow:var(--slack-shadow);color:var(--slack-text-light);display:flex;padding:8px 20px 8px 8px;transition:background-color .1s ease}.fl-slack .fl-slack-message:hover{background-color:var(--slack-hover-light)}.fl-slack .fl-avatar{align-items:center;background-color:currentColor;border-radius:4px;display:flex;flex-shrink:0;height:var(--slack-avatar-size);justify-content:center;margin-right:8px;width:var(--slack-avatar-size)}.fl-slack .fl-type-icon{color:#fff;font-size:16px;font-weight:700}.fl-slack .fl-message-content{flex:1;min-width:0}.fl-slack .fl-message-text{font-size:15px;line-height:1.46668;word-break:break-word}.fl-slack .fl-actions{opacity:0;position:absolute;right:6px;top:8px;transition:opacity .1s ease;visibility:hidden}.fl-slack .fl-slack-message:hover .fl-actions{opacity:1;visibility:visible}.fl-slack .fl-close{align-items:center;background:none;border:none;border-radius:4px;color:var(--slack-text-secondary-light);cursor:pointer;display:flex;justify-content:center;padding:4px}.fl-slack .fl-close:hover{background-color:var(--slack-hover-light);color:var(--slack-text-light)}.fl-slack.fl-success .fl-avatar{color:var(--slack-success)}.fl-slack.fl-info .fl-avatar{color:var(--slack-info)}.fl-slack.fl-warning .fl-avatar{color:var(--slack-warning)}.fl-slack.fl-error .fl-avatar{color:var(--slack-error)}.fl-slack.fl-rtl{direction:rtl}.fl-slack.fl-rtl .fl-avatar{margin-left:8px;margin-right:0}.fl-slack.fl-rtl .fl-username{margin-left:4px;margin-right:0}.fl-slack.fl-rtl .fl-actions{left:6px;right:auto}.fl-slack.fl-rtl .fl-slack-message{padding:8px 8px 8px 20px}@media (prefers-reduced-motion:reduce){.fl-slack{animation:none}}.fl-slack.fl-auto-dark .fl-slack-message,body.fl-dark .fl-slack .fl-slack-message,html.fl-dark .fl-slack .fl-slack-message{background-color:var(--slack-bg-dark);border-color:var(--slack-border-dark);box-shadow:var(--slack-shadow-dark);color:var(--slack-text-dark)}.fl-slack.fl-auto-dark .fl-slack-message:hover,body.fl-dark .fl-slack .fl-slack-message:hover,html.fl-dark .fl-slack .fl-slack-message:hover{background-color:var(--slack-hover-dark)}.fl-slack.fl-auto-dark .fl-close,body.fl-dark .fl-slack .fl-close,html.fl-dark .fl-slack .fl-close{color:var(--slack-text-secondary-dark)}.fl-slack.fl-auto-dark .fl-close:hover,body.fl-dark .fl-slack .fl-close:hover,html.fl-dark .fl-slack .fl-close:hover{background-color:var(--slack-hover-dark);color:var(--slack-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";e.addTheme("slack",{render:e=>{const{type:s,message:i}=e,n="error"===s||"warning"===s;return`\n <div class="fl-slack fl-${s}" role="${n?"alert":"status"}" aria-live="${n?"assertive":"polite"}" aria-atomic="true">\n <div class="fl-slack-message">\n <div class="fl-avatar">\n ${(()=>{switch(s){case"success":return'<div class="fl-type-icon fl-success-icon">✓</div>';case"error":return'<div class="fl-type-icon fl-error-icon">✕</div>';case"warning":return'<div class="fl-type-icon fl-warning-icon">!</div>';case"info":return'<div class="fl-type-icon fl-info-icon">i</div>'}return""})()}\n </div>\n <div class="fl-message-content">\n <div class="fl-message-text">${i}</div>\n </div>\n <div class="fl-actions">\n <button class="fl-close" aria-label="Close ${s} message">\n <svg viewBox="0 0 20 20" width="16" height="16">\n <path fill="currentColor" d="M10 8.586L6.707 5.293a1 1 0 00-1.414 1.414L8.586 10l-3.293 3.293a1 1 0 101.414 1.414L10 11.414l3.293 3.293a1 1 0 001.414-1.414L11.414 10l3.293-3.293a1 1 0 00-1.414-1.414L10 8.586z"/>\n </svg>\n </button>\n </div>\n </div>\n </div>`}})}));
|
||||
@@ -0,0 +1,147 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
|
||||
class ExamplesController extends AbstractController
|
||||
{
|
||||
#[Route('/examples', name: 'app_examples')]
|
||||
public function index(): Response
|
||||
{
|
||||
flash()->info('Browse through our examples to see PHPFlasher in action!');
|
||||
|
||||
return $this->render('examples/index.html.twig');
|
||||
}
|
||||
|
||||
#[Route('/examples/form', name: 'app_form_example')]
|
||||
public function formExample(Request $request): Response
|
||||
{
|
||||
if ($request->isMethod('POST')) {
|
||||
$name = $request->request->get('name');
|
||||
$email = $request->request->get('email');
|
||||
|
||||
// Simulate validation
|
||||
$errors = [];
|
||||
|
||||
if (empty($name)) {
|
||||
$errors['name'] = 'Name is required';
|
||||
}
|
||||
|
||||
if (empty($email)) {
|
||||
$errors['email'] = 'Email is required';
|
||||
} elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
||||
$errors['email'] = 'Invalid email format';
|
||||
}
|
||||
|
||||
// Display appropriate notifications
|
||||
if (empty($errors)) {
|
||||
flash()->success('Form submitted successfully! Thank you, ' . $name);
|
||||
} else {
|
||||
foreach ($errors as $field => $message) {
|
||||
flash()->error($message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->render('examples/form.html.twig');
|
||||
}
|
||||
|
||||
#[Route('/examples/ajax', name: 'app_ajax_example')]
|
||||
public function ajaxExample(): Response
|
||||
{
|
||||
return $this->render('examples/ajax.html.twig');
|
||||
}
|
||||
|
||||
#[Route('/examples/ajax/process', name: 'app_ajax_process', methods: ['POST'])]
|
||||
public function ajaxProcess(Request $request): JsonResponse
|
||||
{
|
||||
if (!$request->isXmlHttpRequest()) {
|
||||
return new JsonResponse(['error' => 'AJAX requests only'], 400);
|
||||
}
|
||||
|
||||
$action = $request->request->get('action');
|
||||
$success = mt_rand(0, 10) > 2; // 80% success rate for demo
|
||||
|
||||
if ($success) {
|
||||
switch ($action) {
|
||||
case 'save':
|
||||
flash()->success('Data saved successfully!');
|
||||
break;
|
||||
case 'update':
|
||||
flash()->success('Record updated successfully!');
|
||||
break;
|
||||
case 'delete':
|
||||
flash()->info('Item has been deleted.');
|
||||
break;
|
||||
default:
|
||||
flash()->success('Operation completed successfully!');
|
||||
}
|
||||
|
||||
return new JsonResponse(['success' => true]);
|
||||
} else {
|
||||
// Simulate errors
|
||||
flash()->error('An error occurred while processing your request. Please try again.');
|
||||
return new JsonResponse(['success' => false], 500);
|
||||
}
|
||||
}
|
||||
|
||||
#[Route('/examples/real-world', name: 'app_real_world')]
|
||||
public function realWorldExamples(): Response
|
||||
{
|
||||
return $this->render('examples/real-world.html.twig');
|
||||
}
|
||||
|
||||
#[Route('/examples/real-world/user-registration', name: 'app_example_user_registration')]
|
||||
public function userRegistration(Request $request): Response
|
||||
{
|
||||
if ($request->isMethod('POST')) {
|
||||
// Simulate user registration
|
||||
$username = $request->request->get('username');
|
||||
|
||||
if (!empty($username)) {
|
||||
flash()->option('timeout', 5000)
|
||||
->option('showProgressbar', true)
|
||||
->success('Registration successful! Welcome, ' . $username . '!');
|
||||
|
||||
// Send additional notification about email verification
|
||||
flash()->option('timeout', 8000)
|
||||
->info('A verification email has been sent to your inbox.');
|
||||
} else {
|
||||
flash()->error('Username is required.');
|
||||
}
|
||||
}
|
||||
|
||||
return $this->render('examples/user-registration.html.twig');
|
||||
}
|
||||
|
||||
#[Route('/examples/real-world/shopping-cart', name: 'app_example_shopping_cart')]
|
||||
public function shoppingCart(): Response
|
||||
{
|
||||
return $this->render('examples/shopping-cart.html.twig');
|
||||
}
|
||||
|
||||
#[Route('/examples/real-world/add-to-cart', name: 'app_add_to_cart', methods: ['POST'])]
|
||||
public function addToCart(Request $request): JsonResponse
|
||||
{
|
||||
if (!$request->isXmlHttpRequest()) {
|
||||
return new JsonResponse(['error' => 'AJAX requests only'], 400);
|
||||
}
|
||||
|
||||
$productId = $request->request->get('product_id');
|
||||
$productName = $request->request->get('product_name', 'Product');
|
||||
|
||||
// Simulate adding to cart
|
||||
flash()->option('position', 'bottom-right')
|
||||
->option('showCloseButton', true)
|
||||
->success($productName . ' added to your cart!');
|
||||
|
||||
return new JsonResponse(['success' => true]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
|
||||
class FeaturesController extends AbstractController
|
||||
{
|
||||
#[Route('/features', name: 'app_features')]
|
||||
public function index(): Response
|
||||
{
|
||||
// Demonstrate a few different notification types
|
||||
flash()->success('Explore the features of PHPFlasher!');
|
||||
flash()->option('timeout', 8000)
|
||||
->info('Click on the links to see each feature in action.');
|
||||
|
||||
return $this->render('features/index.html.twig');
|
||||
}
|
||||
|
||||
#[Route('/features/types', name: 'app_types')]
|
||||
public function types(): Response
|
||||
{
|
||||
// Demonstrate different notification types
|
||||
flash()->success('This is a success notification!');
|
||||
flash()->info('This is an info notification!');
|
||||
flash()->warning('This is a warning notification!');
|
||||
flash()->error('This is an error notification!');
|
||||
|
||||
return $this->render('features/types.html.twig');
|
||||
}
|
||||
|
||||
#[Route('/features/positions', name: 'app_positions')]
|
||||
public function positions(): Response
|
||||
{
|
||||
// Notifications with different positions
|
||||
flash()->option('position', 'top-right')->success('This notification appears in the top-right corner!');
|
||||
|
||||
return $this->render('features/positions.html.twig');
|
||||
}
|
||||
|
||||
#[Route('/features/options', name: 'app_options')]
|
||||
public function options(): Response
|
||||
{
|
||||
// Notification with custom options
|
||||
flash()->option('timeout', 8000)
|
||||
->option('position', 'bottom-center')
|
||||
->option('showProgressbar', true)
|
||||
->success('This notification has custom options!');
|
||||
|
||||
return $this->render('features/options.html.twig');
|
||||
}
|
||||
|
||||
#[Route('/features/plugins', name: 'app_plugins')]
|
||||
public function plugins(): Response
|
||||
{
|
||||
// Plugin examples
|
||||
flash()->addSuccess('This shows how PHPFlasher can be extended with plugins!');
|
||||
|
||||
return $this->render('features/plugins.html.twig');
|
||||
}
|
||||
|
||||
#[Route('/features/presets', name: 'app_presets')]
|
||||
public function presets(): Response
|
||||
{
|
||||
// Example of using presets
|
||||
flash()->preset('profile.updated')
|
||||
->success('Your profile has been updated successfully!');
|
||||
|
||||
flash()->preset('item.deleted')
|
||||
->info('The item has been deleted.');
|
||||
|
||||
return $this->render('features/presets.html.twig');
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,12 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Entity\Book;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
|
||||
@@ -12,18 +15,68 @@ class HomeController extends AbstractController
|
||||
#[Route('/', name: 'app_home')]
|
||||
public function index(): Response
|
||||
{
|
||||
sweetalert()->timerProgressBar()->success('hello from Home Controller');
|
||||
noty()->layout('topCenter')->success('hello from Home Controller');
|
||||
notyf()->ripple(false)->warning('hello from Home Controller');
|
||||
toastr()->positionClass('toast-bottom-left')->error('hello from Home Controller');
|
||||
flash()->use('flasher')->success('hello from flasher factory');
|
||||
|
||||
flash()->created(new Book('lord of the rings'));
|
||||
flash()->saved(new Book('harry potter'));
|
||||
|
||||
flash()->updated();
|
||||
flash()->deleted();
|
||||
// Welcome notification
|
||||
flash()->option('timeout', 10000)
|
||||
->info('Welcome to the PHPFlasher Demo! 👋 Explore different features using the navigation.');
|
||||
|
||||
return $this->render('home/index.html.twig');
|
||||
}
|
||||
|
||||
#[Route('/installation', name: 'app_installation')]
|
||||
public function installation(): Response
|
||||
{
|
||||
return $this->render('home/installation.html.twig');
|
||||
}
|
||||
|
||||
#[Route('/basic-usage', name: 'app_basic_usage')]
|
||||
public function basicUsage(): Response
|
||||
{
|
||||
// Basic success notification
|
||||
flash()->success('This is a success notification!');
|
||||
|
||||
return $this->render('home/basic-usage.html.twig');
|
||||
}
|
||||
|
||||
#[Route('/playground', name: 'app_playground')]
|
||||
public function playground(): Response
|
||||
{
|
||||
return $this->render('home/playground.html.twig');
|
||||
}
|
||||
|
||||
#[Route('/theme-builder', name: 'app_theme_builder')]
|
||||
public function themeBuilder(): Response
|
||||
{
|
||||
return $this->render('home/theme-builder.html.twig');
|
||||
}
|
||||
|
||||
#[Route('/show-notification', name: 'app_show_notification', methods: ['POST'])]
|
||||
public function showNotification(Request $request): JsonResponse
|
||||
{
|
||||
if (!$request->isXmlHttpRequest()) {
|
||||
return new JsonResponse(['error' => 'AJAX requests only'], 400);
|
||||
}
|
||||
|
||||
$data = json_decode($request->getContent(), true);
|
||||
$type = $data['type'] ?? 'info';
|
||||
$message = $data['message'] ?? 'This is a notification!';
|
||||
|
||||
// Create notification based on type
|
||||
switch ($type) {
|
||||
case 'success':
|
||||
flash()->success($message);
|
||||
break;
|
||||
case 'error':
|
||||
flash()->error($message);
|
||||
break;
|
||||
case 'warning':
|
||||
flash()->warning($message);
|
||||
break;
|
||||
case 'info':
|
||||
default:
|
||||
flash()->info($message);
|
||||
break;
|
||||
}
|
||||
|
||||
return new JsonResponse(['status' => 'success']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
|
||||
class IntegrationController extends AbstractController
|
||||
{
|
||||
#[Route('/integration/api', name: 'app_integration_api')]
|
||||
public function apiIntegration(): Response
|
||||
{
|
||||
// Example of how PHPFlasher can work with API responses
|
||||
flash()->option('position', 'bottom-center')
|
||||
->success('API request processed successfully!');
|
||||
|
||||
return $this->render('integration/api.html.twig');
|
||||
}
|
||||
|
||||
#[Route('/integration/translation', name: 'app_integration_translation')]
|
||||
public function translationIntegration(): Response
|
||||
{
|
||||
// Example using translation integration
|
||||
flash()->option('translate', true)
|
||||
->success('messages.success.operation_completed');
|
||||
|
||||
return $this->render('integration/translation.html.twig');
|
||||
}
|
||||
|
||||
#[Route('/integration/symfony-flashbag', name: 'app_integration_flashbag')]
|
||||
public function symfonyFlashbag(): Response
|
||||
{
|
||||
// Add message to Symfony flash bag to demonstrate integration
|
||||
$this->addFlash('success', 'This message was added using Symfony\'s addFlash method!');
|
||||
$this->addFlash('error', 'This error was added using Symfony\'s addFlash method!');
|
||||
$this->addFlash('warning', 'This warning was added using Symfony\'s addFlash method!');
|
||||
|
||||
return $this->render('integration/flashbag.html.twig');
|
||||
}
|
||||
|
||||
#[Route('/integration/custom-templates', name: 'app_integration_templates')]
|
||||
public function customTemplates(): Response
|
||||
{
|
||||
// Example using custom templates
|
||||
flash()->option('template', 'custom_template')
|
||||
->success('This notification uses a custom template!');
|
||||
|
||||
return $this->render('integration/custom-templates.html.twig');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
|
||||
class ThemesController extends AbstractController
|
||||
{
|
||||
#[Route('/themes', name: 'app_themes')]
|
||||
public function index(): Response
|
||||
{
|
||||
// Show default theme notification
|
||||
flash()->success('This is a notification with the default theme!');
|
||||
|
||||
return $this->render('themes/index.html.twig');
|
||||
}
|
||||
|
||||
#[Route('/themes/flasher', name: 'app_theme_flasher')]
|
||||
public function flasherTheme(): Response
|
||||
{
|
||||
// Using the Flasher theme
|
||||
flash()->option('theme', 'flasher')
|
||||
->success('This notification uses the Flasher theme!');
|
||||
|
||||
return $this->render('themes/flasher.html.twig');
|
||||
}
|
||||
|
||||
#[Route('/themes/crystal', name: 'app_theme_crystal')]
|
||||
public function crystalTheme(): Response
|
||||
{
|
||||
// Using the Crystal theme
|
||||
flash()->option('theme', 'crystal')
|
||||
->success('This notification uses the Crystal theme!');
|
||||
|
||||
return $this->render('themes/crystal.html.twig');
|
||||
}
|
||||
|
||||
#[Route('/themes/emerald', name: 'app_theme_emerald')]
|
||||
public function emeraldTheme(): Response
|
||||
{
|
||||
// Using the Emerald theme
|
||||
flash()->option('theme', 'emerald')
|
||||
->success('This notification uses the Emerald theme!');
|
||||
|
||||
return $this->render('themes/emerald.html.twig');
|
||||
}
|
||||
|
||||
#[Route('/themes/sapphire', name: 'app_theme_sapphire')]
|
||||
public function sapphireTheme(): Response
|
||||
{
|
||||
// Using the Sapphire theme
|
||||
flash()->option('theme', 'sapphire')
|
||||
->success('This notification uses the Sapphire theme!');
|
||||
|
||||
return $this->render('themes/sapphire.html.twig');
|
||||
}
|
||||
|
||||
#[Route('/themes/amazon', name: 'app_theme_amazon')]
|
||||
public function amazonTheme(): Response
|
||||
{
|
||||
// Using the Amazon theme
|
||||
flash()->option('theme', 'amazon')
|
||||
->success('This notification uses the Amazon theme!');
|
||||
|
||||
return $this->render('themes/amazon.html.twig');
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,231 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>{% block title %}Welcome!{% endblock %}</title>
|
||||
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 128 128%22><text y=%221.2em%22 font-size=%2296%22>⚫️</text><text y=%221.3em%22 x=%220.2em%22 font-size=%2276%22 fill=%22%23fff%22>sf</text></svg>">
|
||||
{% block stylesheets %}
|
||||
{% endblock %}
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{% block title %}PHPFlasher Demo{% endblock %}</title>
|
||||
|
||||
{% block javascripts %}
|
||||
{% endblock %}
|
||||
</head>
|
||||
<body>
|
||||
{% block body %}{% endblock %}
|
||||
</body>
|
||||
{# 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">
|
||||
|
||||
{# Custom styles using Tailwind #}
|
||||
<script type="text/tailwindcss">
|
||||
@layer components {
|
||||
.btn {
|
||||
@apply px-4 py-2 rounded-md font-medium transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-opacity-50;
|
||||
}
|
||||
.btn-primary {
|
||||
@apply bg-indigo-600 text-white hover:bg-indigo-700 focus:ring-indigo-500;
|
||||
}
|
||||
.btn-success {
|
||||
@apply bg-emerald-600 text-white hover:bg-emerald-700 focus:ring-emerald-500;
|
||||
}
|
||||
.btn-danger {
|
||||
@apply bg-rose-600 text-white hover:bg-rose-700 focus:ring-rose-500;
|
||||
}
|
||||
.btn-warning {
|
||||
@apply bg-amber-500 text-white hover:bg-amber-600 focus:ring-amber-400;
|
||||
}
|
||||
.btn-info {
|
||||
@apply bg-sky-500 text-white hover:bg-sky-600 focus:ring-sky-400;
|
||||
}
|
||||
.btn-outline {
|
||||
@apply border border-gray-300 text-gray-700 bg-white hover:bg-gray-50 focus:ring-indigo-500;
|
||||
}
|
||||
.code-block {
|
||||
@apply rounded-lg overflow-hidden shadow-lg my-6;
|
||||
}
|
||||
.code-header {
|
||||
@apply bg-gray-800 text-gray-200 px-4 py-2 flex justify-between items-center;
|
||||
}
|
||||
.theme-card {
|
||||
@apply rounded-lg overflow-hidden bg-white shadow-md hover:shadow-lg transition duration-300;
|
||||
}
|
||||
.theme-preview {
|
||||
@apply h-32 flex items-center justify-center;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
{% block stylesheets %}{% endblock %}
|
||||
</head>
|
||||
<body class="bg-gray-50 antialiased text-gray-900 min-h-screen flex flex-col">
|
||||
<header class="bg-indigo-600 text-white shadow-md">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex justify-between items-center py-4">
|
||||
<div class="flex items-center space-x-3">
|
||||
<div class="flex items-center">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-8 w-8" 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="ml-2 text-2xl font-bold">PHPFlasher</span>
|
||||
</div>
|
||||
<span class="hidden md:inline text-indigo-200">Beautiful Notifications for Your PHP Applications</span>
|
||||
</div>
|
||||
<div class="hidden md:flex space-x-4">
|
||||
<a href="https://github.com/php-flasher/flasher" class="text-indigo-100 hover:text-white transition flex items-center" target="_blank">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-1" 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>
|
||||
GitHub
|
||||
</a>
|
||||
<a href="https://php-flasher.io" class="text-indigo-100 hover:text-white transition flex items-center" target="_blank">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 12a9 9 0 01-9 9m9-9a9 9 0 00-9-9m9 9H3m9 9a9 9 0 01-9-9m9 9c1.657 0 3-4.03 3-9s-1.343-9-3-9m0 18c-1.657 0-3-4.03-3-9s1.343-9 3-9m-9 9a9 9 0 019-9" />
|
||||
</svg>
|
||||
Documentation
|
||||
</a>
|
||||
</div>
|
||||
<button id="mobile-menu-button" class="md:hidden text-white">
|
||||
<svg xmlns="http://www.w3.org/2000/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>
|
||||
</header>
|
||||
|
||||
<div id="mobile-menu" class="hidden md:hidden bg-indigo-700 text-white">
|
||||
<div class="px-4 pt-2 pb-4 space-y-3">
|
||||
<a href="{{ path('app_home') }}" class="block py-2 hover:bg-indigo-600 rounded px-2">Home</a>
|
||||
<a href="{{ path('app_features') }}" class="block py-2 hover:bg-indigo-600 rounded px-2">Features</a>
|
||||
<a href="{{ path('app_themes') }}" class="block py-2 hover:bg-indigo-600 rounded px-2">Themes</a>
|
||||
<a href="{{ path('app_examples') }}" class="block py-2 hover:bg-indigo-600 rounded px-2">Examples</a>
|
||||
<a href="{{ path('app_playground') }}" class="block py-2 hover:bg-indigo-600 rounded px-2">Playground</a>
|
||||
<a href="https://github.com/php-flasher/flasher" class="block py-2 hover:bg-indigo-600 rounded px-2">GitHub</a>
|
||||
<a href="https://php-flasher.io" class="block py-2 hover:bg-indigo-600 rounded px-2">Documentation</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-1">
|
||||
<aside class="hidden md:block bg-white w-64 border-r border-gray-200 shadow-sm">
|
||||
<div class="p-6 border-b border-gray-200">
|
||||
<h2 class="text-lg font-semibold text-gray-800">Navigation</h2>
|
||||
<p class="text-sm text-gray-500 mt-1">Explore PHPFlasher</p>
|
||||
</div>
|
||||
<nav class="py-4">
|
||||
<div class="px-6 py-2 text-xs font-semibold text-gray-500 uppercase tracking-wider">
|
||||
Getting Started
|
||||
</div>
|
||||
<a href="{{ path('app_home') }}" class="block px-6 py-2 text-gray-700 hover:bg-indigo-50 hover:text-indigo-700 {% if app.request.get('_route') == 'app_home' %}bg-indigo-50 text-indigo-700 border-r-4 border-indigo-500{% endif %}">
|
||||
Home
|
||||
</a>
|
||||
<a href="{{ path('app_installation') }}" class="block px-6 py-2 text-gray-700 hover:bg-indigo-50 hover:text-indigo-700 {% if app.request.get('_route') == 'app_installation' %}bg-indigo-50 text-indigo-700 border-r-4 border-indigo-500{% endif %}">
|
||||
Installation
|
||||
</a>
|
||||
<a href="{{ path('app_basic_usage') }}" class="block px-6 py-2 text-gray-700 hover:bg-indigo-50 hover:text-indigo-700 {% if app.request.get('_route') == 'app_basic_usage' %}bg-indigo-50 text-indigo-700 border-r-4 border-indigo-500{% endif %}">
|
||||
Basic Usage
|
||||
</a>
|
||||
|
||||
<div class="px-6 py-2 mt-4 text-xs font-semibold text-gray-500 uppercase tracking-wider">
|
||||
Features
|
||||
</div>
|
||||
<a href="{{ path('app_types') }}" class="block px-6 py-2 text-gray-700 hover:bg-indigo-50 hover:text-indigo-700 {% if app.request.get('_route') == 'app_types' %}bg-indigo-50 text-indigo-700 border-r-4 border-indigo-500{% endif %}">
|
||||
Notification Types
|
||||
</a>
|
||||
<a href="{{ path('app_positions') }}" class="block px-6 py-2 text-gray-700 hover:bg-indigo-50 hover:text-indigo-700 {% if app.request.get('_route') == 'app_positions' %}bg-indigo-50 text-indigo-700 border-r-4 border-indigo-500{% endif %}">
|
||||
Positions
|
||||
</a>
|
||||
<a href="{{ path('app_themes') }}" class="block px-6 py-2 text-gray-700 hover:bg-indigo-50 hover:text-indigo-700 {% if app.request.get('_route') == 'app_themes' %}bg-indigo-50 text-indigo-700 border-r-4 border-indigo-500{% endif %}">
|
||||
Themes
|
||||
</a>
|
||||
<a href="{{ path('app_options') }}" class="block px-6 py-2 text-gray-700 hover:bg-indigo-50 hover:text-indigo-700 {% if app.request.get('_route') == 'app_options' %}bg-indigo-50 text-indigo-700 border-r-4 border-indigo-500{% endif %}">
|
||||
Options & Configuration
|
||||
</a>
|
||||
<a href="{{ path('app_plugins') }}" class="block px-6 py-2 text-gray-700 hover:bg-indigo-50 hover:text-indigo-700 {% if app.request.get('_route') == 'app_plugins' %}bg-indigo-50 text-indigo-700 border-r-4 border-indigo-500{% endif %}">
|
||||
Plugins
|
||||
</a>
|
||||
|
||||
<div class="px-6 py-2 mt-4 text-xs font-semibold text-gray-500 uppercase tracking-wider">
|
||||
Examples
|
||||
</div>
|
||||
<a href="{{ path('app_form_example') }}" class="block px-6 py-2 text-gray-700 hover:bg-indigo-50 hover:text-indigo-700 {% if app.request.get('_route') == 'app_form_example' %}bg-indigo-50 text-indigo-700 border-r-4 border-indigo-500{% endif %}">
|
||||
Form Validation
|
||||
</a>
|
||||
<a href="{{ path('app_ajax_example') }}" class="block px-6 py-2 text-gray-700 hover:bg-indigo-50 hover:text-indigo-700 {% if app.request.get('_route') == 'app_ajax_example' %}bg-indigo-50 text-indigo-700 border-r-4 border-indigo-500{% endif %}">
|
||||
AJAX Requests
|
||||
</a>
|
||||
<a href="{{ path('app_presets') }}" class="block px-6 py-2 text-gray-700 hover:bg-indigo-50 hover:text-indigo-700 {% if app.request.get('_route') == 'app_presets' %}bg-indigo-50 text-indigo-700 border-r-4 border-indigo-500{% endif %}">
|
||||
Presets
|
||||
</a>
|
||||
<a href="{{ path('app_real_world') }}" class="block px-6 py-2 text-gray-700 hover:bg-indigo-50 hover:text-indigo-700 {% if app.request.get('_route') == 'app_real_world' %}bg-indigo-50 text-indigo-700 border-r-4 border-indigo-500{% endif %}">
|
||||
Real-World Examples
|
||||
</a>
|
||||
|
||||
<div class="px-6 py-2 mt-4 text-xs font-semibold text-gray-500 uppercase tracking-wider">
|
||||
Interactive
|
||||
</div>
|
||||
<a href="{{ path('app_playground') }}" class="block px-6 py-2 text-gray-700 hover:bg-indigo-50 hover:text-indigo-700 {% if app.request.get('_route') == 'app_playground' %}bg-indigo-50 text-indigo-700 border-r-4 border-indigo-500{% endif %}">
|
||||
Interactive Playground
|
||||
</a>
|
||||
<a href="{{ path('app_theme_builder') }}" class="block px-6 py-2 text-gray-700 hover:bg-indigo-50 hover:text-indigo-700 {% if app.request.get('_route') == 'app_theme_builder' %}bg-indigo-50 text-indigo-700 border-r-4 border-indigo-500{% endif %}">
|
||||
Theme Builder
|
||||
</a>
|
||||
</nav>
|
||||
</aside>
|
||||
|
||||
<main class="flex-1 overflow-x-hidden">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
||||
<div class="mb-6">
|
||||
<h1 class="text-3xl font-bold text-gray-900">{% block page_title %}Welcome to PHPFlasher{% endblock %}</h1>
|
||||
<p class="mt-2 text-lg text-gray-600">{% block page_subtitle %}A powerful notification system for PHP applications{% endblock %}</p>
|
||||
</div>
|
||||
|
||||
{% block content %}{% endblock %}
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<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="text-center md:text-left">
|
||||
<p class="text-gray-500">
|
||||
© {{ "now"|date("Y") }} PHPFlasher. Made with ❤️ by <a href="https://github.com/yoeunes" class="text-indigo-600 hover:text-indigo-500">Younes ENNAJI</a>
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex space-x-6">
|
||||
<a href="https://github.com/php-flasher/flasher" class="text-gray-500 hover:text-gray-700">
|
||||
<span class="sr-only">GitHub</span>
|
||||
<svg class="h-6 w-6" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path fill-rule="evenodd" d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z" clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
</a>
|
||||
<a href="https://php-flasher.io" class="text-gray-500 hover:text-gray-700">
|
||||
<span class="sr-only">Website</span>
|
||||
<svg xmlns="http://www.w3.org/2000/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="M3.055 11H5a2 2 0 012 2v1a2 2 0 002 2 2 2 0 012 2v2.945M8 3.935V5.5A2.5 2.5 0 0010.5 8h.5a2 2 0 012 2 2 2 0 104 0 2 2 0 012-2h1.064M15 20.488V18a2 2 0 012-2h3.064M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
{# Prism.js for syntax highlighting #}
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-core.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/autoloader/prism-autoloader.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>
|
||||
|
||||
{# Mobile menu toggle script #}
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const mobileMenuButton = document.getElementById('mobile-menu-button');
|
||||
const mobileMenu = document.getElementById('mobile-menu');
|
||||
|
||||
if (mobileMenuButton && mobileMenu) {
|
||||
mobileMenuButton.addEventListener('click', function() {
|
||||
mobileMenu.classList.toggle('hidden');
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
{% block javascripts %}{% endblock %}
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,232 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block title %}PHPFlasher - Notification Positions{% endblock %}
|
||||
|
||||
{% block page_title %}Notification Positions{% endblock %}
|
||||
{% block page_subtitle %}Control where your notifications appear on the screen{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="bg-white rounded-lg shadow-md overflow-hidden mb-8">
|
||||
<div class="p-6">
|
||||
<h2 class="text-xl font-bold mb-4">Available Positions</h2>
|
||||
<p class="text-gray-600 mb-6">
|
||||
PHPFlasher allows you to position your notifications in different areas of the screen.
|
||||
You can choose from 9 different positions to best fit your design and user experience needs.
|
||||
</p>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-8">
|
||||
<div class="relative h-72 bg-gray-100 rounded-lg overflow-hidden border border-gray-200">
|
||||
<div class="absolute top-2 left-2 bg-indigo-100 text-indigo-800 px-3 py-1 rounded-lg text-sm">top-left</div>
|
||||
<div class="absolute top-2 right-2 bg-white shadow-md p-3 rounded w-3/4">
|
||||
<div class="h-2 w-12 bg-indigo-500 mb-2 rounded"></div>
|
||||
<div class="h-2 w-20 bg-gray-300 mb-2 rounded"></div>
|
||||
<div class="h-2 w-16 bg-gray-300 rounded"></div>
|
||||
</div>
|
||||
<button class="absolute bottom-4 left-1/2 transform -translate-x-1/2 btn btn-primary notification-position" data-position="top-left">
|
||||
Show Notification
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="relative h-72 bg-gray-100 rounded-lg overflow-hidden border border-gray-200">
|
||||
<div class="absolute top-2 left-1/2 transform -translate-x-1/2 bg-indigo-100 text-indigo-800 px-3 py-1 rounded-lg text-sm">top-center</div>
|
||||
<div class="absolute top-2 left-1/2 transform -translate-x-1/2 bg-white shadow-md p-3 rounded w-3/4">
|
||||
<div class="h-2 w-12 bg-indigo-500 mb-2 rounded"></div>
|
||||
<div class="h-2 w-20 bg-gray-300 mb-2 rounded"></div>
|
||||
<div class="h-2 w-16 bg-gray-300 rounded"></div>
|
||||
</div>
|
||||
<button class="absolute bottom-4 left-1/2 transform -translate-x-1/2 btn btn-primary notification-position" data-position="top-center">
|
||||
Show Notification
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="relative h-72 bg-gray-100 rounded-lg overflow-hidden border border-gray-200">
|
||||
<div class="absolute top-2 right-2 bg-indigo-100 text-indigo-800 px-3 py-1 rounded-lg text-sm">top-right</div>
|
||||
<div class="absolute top-2 right-2 bg-white shadow-md p-3 rounded w-3/4">
|
||||
<div class="h-2 w-12 bg-indigo-500 mb-2 rounded"></div>
|
||||
<div class="h-2 w-20 bg-gray-300 mb-2 rounded"></div>
|
||||
<div class="h-2 w-16 bg-gray-300 rounded"></div>
|
||||
</div>
|
||||
<button class="absolute bottom-4 left-1/2 transform -translate-x-1/2 btn btn-primary notification-position" data-position="top-right">
|
||||
Show Notification
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="relative h-72 bg-gray-100 rounded-lg overflow-hidden border border-gray-200">
|
||||
<div class="absolute top-1/2 left-2 transform -translate-y-1/2 bg-indigo-100 text-indigo-800 px-3 py-1 rounded-lg text-sm">center-left</div>
|
||||
<div class="absolute top-1/2 left-2 transform -translate-y-1/2 bg-white shadow-md p-3 rounded w-3/4">
|
||||
<div class="h-2 w-12 bg-indigo-500 mb-2 rounded"></div>
|
||||
<div class="h-2 w-20 bg-gray-300 mb-2 rounded"></div>
|
||||
<div class="h-2 w-16 bg-gray-300 rounded"></div>
|
||||
</div>
|
||||
<button class="absolute bottom-4 left-1/2 transform -translate-x-1/2 btn btn-primary notification-position" data-position="center-left">
|
||||
Show Notification
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="relative h-72 bg-gray-100 rounded-lg overflow-hidden border border-gray-200">
|
||||
<div class="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 bg-indigo-100 text-indigo-800 px-3 py-1 rounded-lg text-sm">center</div>
|
||||
<div class="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 bg-white shadow-md p-3 rounded w-3/4">
|
||||
<div class="h-2 w-12 bg-indigo-500 mb-2 rounded"></div>
|
||||
<div class="h-2 w-20 bg-gray-300 mb-2 rounded"></div>
|
||||
<div class="h-2 w-16 bg-gray-300 rounded"></div>
|
||||
</div>
|
||||
<button class="absolute bottom-4 left-1/2 transform -translate-x-1/2 btn btn-primary notification-position" data-position="center">
|
||||
Show Notification
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="relative h-72 bg-gray-100 rounded-lg overflow-hidden border border-gray-200">
|
||||
<div class="absolute top-1/2 right-2 transform -translate-y-1/2 bg-indigo-100 text-indigo-800 px-3 py-1 rounded-lg text-sm">center-right</div>
|
||||
<div class="absolute top-1/2 right-2 transform -translate-y-1/2 bg-white shadow-md p-3 rounded w-3/4">
|
||||
<div class="h-2 w-12 bg-indigo-500 mb-2 rounded"></div>
|
||||
<div class="h-2 w-20 bg-gray-300 mb-2 rounded"></div>
|
||||
<div class="h-2 w-16 bg-gray-300 rounded"></div>
|
||||
</div>
|
||||
<button class="absolute bottom-4 left-1/2 transform -translate-x-1/2 btn btn-primary notification-position" data-position="center-right">
|
||||
Show Notification
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="relative h-72 bg-gray-100 rounded-lg overflow-hidden border border-gray-200">
|
||||
<div class="absolute bottom-2 left-2 bg-indigo-100 text-indigo-800 px-3 py-1 rounded-lg text-sm">bottom-left</div>
|
||||
<div class="absolute bottom-10 left-2 bg-white shadow-md p-3 rounded w-3/4">
|
||||
<div class="h-2 w-12 bg-indigo-500 mb-2 rounded"></div>
|
||||
<div class="h-2 w-20 bg-gray-300 mb-2 rounded"></div>
|
||||
<div class="h-2 w-16 bg-gray-300 rounded"></div>
|
||||
</div>
|
||||
<button class="absolute bottom-4 left-1/2 transform -translate-x-1/2 btn btn-primary notification-position" data-position="bottom-left">
|
||||
Show Notification
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="relative h-72 bg-gray-100 rounded-lg overflow-hidden border border-gray-200">
|
||||
<div class="absolute bottom-2 left-1/2 transform -translate-x-1/2 bg-indigo-100 text-indigo-800 px-3 py-1 rounded-lg text-sm">bottom-center</div>
|
||||
<div class="absolute bottom-10 left-1/2 transform -translate-x-1/2 bg-white shadow-md p-3 rounded w-3/4">
|
||||
<div class="h-2 w-12 bg-indigo-500 mb-2 rounded"></div>
|
||||
<div class="h-2 w-20 bg-gray-300 mb-2 rounded"></div>
|
||||
<div class="h-2 w-16 bg-gray-300 rounded"></div>
|
||||
</div>
|
||||
<button class="absolute bottom-4 left-1/2 transform -translate-x-1/2 btn btn-primary notification-position" data-position="bottom-center">
|
||||
Show Notification
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="relative h-72 bg-gray-100 rounded-lg overflow-hidden border border-gray-200">
|
||||
<div class="absolute bottom-2 right-2 bg-indigo-100 text-indigo-800 px-3 py-1 rounded-lg text-sm">bottom-right</div>
|
||||
<div class="absolute bottom-10 right-2 bg-white shadow-md p-3 rounded w-3/4">
|
||||
<div class="h-2 w-12 bg-indigo-500 mb-2 rounded"></div>
|
||||
<div class="h-2 w-20 bg-gray-300 mb-2 rounded"></div>
|
||||
<div class="h-2 w-16 bg-gray-300 rounded"></div>
|
||||
</div>
|
||||
<button class="absolute bottom-4 left-1/2 transform -translate-x-1/2 btn btn-primary notification-position" data-position="bottom-right">
|
||||
Show Notification
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-white rounded-lg shadow-md overflow-hidden mb-8">
|
||||
<div class="p-6">
|
||||
<h2 class="text-xl font-bold mb-4">Setting Positions in Code</h2>
|
||||
<p class="text-gray-600 mb-4">
|
||||
You can set the position of notifications in your PHP code using the <code>option()</code> method:
|
||||
</p>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>PHP</span>
|
||||
</div>
|
||||
<pre><code class="language-php">// Top-right position (default)
|
||||
flash()->success('Your changes have been saved.');
|
||||
|
||||
// Bottom-left position
|
||||
flash()->option('position', 'bottom-left')
|
||||
->success('Your changes have been saved.');
|
||||
|
||||
// Top-center position
|
||||
flash()->option('position', 'top-center')
|
||||
->info('You have 3 unread messages.');
|
||||
|
||||
// Center position (middle of the screen)
|
||||
flash()->option('position', 'center')
|
||||
->warning('Your session will expire in 1 minute.');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-white rounded-lg shadow-md overflow-hidden">
|
||||
<div class="p-6">
|
||||
<h2 class="text-xl font-bold mb-4">Global Position Configuration</h2>
|
||||
<p class="text-gray-600 mb-4">
|
||||
You can set a default position for all notifications in your configuration file:
|
||||
</p>
|
||||
|
||||
<div class="code-block mb-6">
|
||||
<div class="code-header">
|
||||
<span>YAML</span>
|
||||
</div>
|
||||
<pre><code class="language-yaml"># config/packages/flasher.yaml
|
||||
flasher:
|
||||
options:
|
||||
position: 'top-right' # Default position for all notifications</code></pre>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 mb-4">
|
||||
Or you can set specific positions for different themes:
|
||||
</p>
|
||||
|
||||
<div class="code-block mb-6">
|
||||
<div class="code-header">
|
||||
<span>YAML</span>
|
||||
</div>
|
||||
<pre><code class="language-yaml"># config/packages/flasher.yaml
|
||||
flasher:
|
||||
themes:
|
||||
amazon:
|
||||
options:
|
||||
position: 'bottom-right'
|
||||
|
||||
sapphire:
|
||||
options:
|
||||
position: 'top-center'</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-center">
|
||||
<a href="{{ path('app_themes') }}" class="btn btn-primary">
|
||||
Explore Themes
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block javascripts %}
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const positionButtons = document.querySelectorAll('.notification-position');
|
||||
|
||||
positionButtons.forEach(button => {
|
||||
button.addEventListener('click', function() {
|
||||
const position = this.getAttribute('data-position');
|
||||
|
||||
// Send AJAX request to show notification
|
||||
fetch('{{ path('app_show_notification') }}', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Requested-With': 'XMLHttpRequest'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
type: 'success',
|
||||
message: 'This notification is at the ' + position + ' position!',
|
||||
options: {
|
||||
position: position
|
||||
}
|
||||
})
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,220 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block title %}PHPFlasher - Notification Types{% endblock %}
|
||||
|
||||
{% block page_title %}Notification Types{% endblock %}
|
||||
{% block page_subtitle %}Display different notification types to communicate various messages{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="bg-white rounded-lg shadow-md overflow-hidden mb-8">
|
||||
<div class="p-6">
|
||||
<h2 class="text-xl font-bold mb-4">Available Notification Types</h2>
|
||||
<p class="text-gray-600 mb-6">
|
||||
PHPFlasher provides four primary notification types to communicate different types of messages to your users.
|
||||
Each type has a distinct visual style to clearly convey the nature of the message.
|
||||
</p>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-8">
|
||||
<div class="border border-gray-200 rounded-lg p-4 hover:shadow-md transition-shadow">
|
||||
<div class="flex items-center mb-3">
|
||||
<div class="bg-emerald-100 p-2 rounded-md mr-3">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 text-emerald-600" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="text-lg font-semibold">Success</h3>
|
||||
</div>
|
||||
<p class="text-gray-600 mb-3">
|
||||
Used for positive feedback when an action has been completed successfully.
|
||||
</p>
|
||||
<div class="code-block mb-3">
|
||||
<div class="code-header">
|
||||
<span>PHP</span>
|
||||
</div>
|
||||
<pre><code class="language-php">flash()->success('Your profile has been updated successfully!');</code></pre>
|
||||
</div>
|
||||
<button class="btn btn-success w-full notification-demo" data-type="success" data-message="This is a success notification!">
|
||||
Show Success Notification
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="border border-gray-200 rounded-lg p-4 hover:shadow-md transition-shadow">
|
||||
<div class="flex items-center mb-3">
|
||||
<div class="bg-rose-100 p-2 rounded-md mr-3">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 text-rose-600" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="text-lg font-semibold">Error</h3>
|
||||
</div>
|
||||
<p class="text-gray-600 mb-3">
|
||||
Used to alert users about errors or problems that need attention.
|
||||
</p>
|
||||
<div class="code-block mb-3">
|
||||
<div class="code-header">
|
||||
<span>PHP</span>
|
||||
</div>
|
||||
<pre><code class="language-php">flash()->error('An error occurred while processing your request.');</code></pre>
|
||||
</div>
|
||||
<button class="btn btn-danger w-full notification-demo" data-type="error" data-message="This is an error notification!">
|
||||
Show Error Notification
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="border border-gray-200 rounded-lg p-4 hover:shadow-md transition-shadow">
|
||||
<div class="flex items-center mb-3">
|
||||
<div class="bg-amber-100 p-2 rounded-md mr-3">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 text-amber-600" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<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" />
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="text-lg font-semibold">Warning</h3>
|
||||
</div>
|
||||
<p class="text-gray-600 mb-3">
|
||||
Used to inform users about potential issues or actions they should be aware of.
|
||||
</p>
|
||||
<div class="code-block mb-3">
|
||||
<div class="code-header">
|
||||
<span>PHP</span>
|
||||
</div>
|
||||
<pre><code class="language-php">flash()->warning('Your subscription will expire in 3 days.');</code></pre>
|
||||
</div>
|
||||
<button class="btn btn-warning w-full notification-demo" data-type="warning" data-message="This is a warning notification!">
|
||||
Show Warning Notification
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="border border-gray-200 rounded-lg p-4 hover:shadow-md transition-shadow">
|
||||
<div class="flex items-center mb-3">
|
||||
<div class="bg-sky-100 p-2 rounded-md mr-3">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 text-sky-600" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<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" />
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="text-lg font-semibold">Info</h3>
|
||||
</div>
|
||||
<p class="text-gray-600 mb-3">
|
||||
Used to provide neutral information or updates to users.
|
||||
</p>
|
||||
<div class="code-block mb-3">
|
||||
<div class="code-header">
|
||||
<span>PHP</span>
|
||||
</div>
|
||||
<pre><code class="language-php">flash()->info('You have 5 unread messages.');</code></pre>
|
||||
</div>
|
||||
<button class="btn btn-info w-full notification-demo" data-type="info" data-message="This is an info notification!">
|
||||
Show Info Notification
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-white rounded-lg shadow-md overflow-hidden mb-8">
|
||||
<div class="p-6">
|
||||
<h2 class="text-xl font-bold mb-4">Usage in Controllers</h2>
|
||||
<p class="text-gray-600 mb-4">
|
||||
Here's how you can use notification types in your Symfony controllers:
|
||||
</p>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>PHP</span>
|
||||
</div>
|
||||
<pre><code class="language-php"><?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
|
||||
class ExampleController extends AbstractController
|
||||
{
|
||||
#[Route('/process-form', name: 'app_process_form')]
|
||||
public function processForm(): Response
|
||||
{
|
||||
// Simulate form processing
|
||||
$success = true;
|
||||
|
||||
if ($success) {
|
||||
// Show success notification
|
||||
flash()->success('Form submitted successfully!');
|
||||
} else {
|
||||
// Show error notification
|
||||
flash()->error('An error occurred while processing the form.');
|
||||
}
|
||||
|
||||
// Show info notification
|
||||
flash()->info('You will receive a confirmation email shortly.');
|
||||
|
||||
// Show warning notification
|
||||
flash()->warning('Please verify your email within 24 hours.');
|
||||
|
||||
return $this->redirectToRoute('app_home');
|
||||
}
|
||||
}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-white rounded-lg shadow-md overflow-hidden">
|
||||
<div class="p-6">
|
||||
<h2 class="text-xl font-bold mb-4">Advanced Usage</h2>
|
||||
<p class="text-gray-600 mb-4">
|
||||
You can combine notification types with other options to create more customized notifications:
|
||||
</p>
|
||||
|
||||
<div class="code-block mb-6">
|
||||
<div class="code-header">
|
||||
<span>PHP</span>
|
||||
</div>
|
||||
<pre><code class="language-php">// Success notification with custom timeout
|
||||
flash()->option('timeout', 8000)
|
||||
->success('Changes saved successfully!');
|
||||
|
||||
// Warning notification with custom position
|
||||
flash()->option('position', 'bottom-center')
|
||||
->warning('Your session will expire soon.');
|
||||
|
||||
// Error notification with progress bar
|
||||
flash()->option('showProgressbar', true)
|
||||
->error('Unable to connect to the server.');</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-center">
|
||||
<a href="{{ path('app_options') }}" class="btn btn-primary">
|
||||
Learn More About Options
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block javascripts %}
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const demoButtons = document.querySelectorAll('.notification-demo');
|
||||
|
||||
demoButtons.forEach(button => {
|
||||
button.addEventListener('click', function() {
|
||||
const type = this.getAttribute('data-type');
|
||||
const message = this.getAttribute('data-message') || 'This is a notification!';
|
||||
|
||||
// Send AJAX request to show notification
|
||||
fetch('{{ path('app_show_notification') }}', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Requested-With': 'XMLHttpRequest'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
type: type,
|
||||
message: message
|
||||
})
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -1,7 +1,97 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block title %}PHPFlasher{% endblock %}
|
||||
{% block title %}PHPFlasher Features{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
{% block page_title %}PHPFlasher Features{% endblock %}
|
||||
{% block page_subtitle %}Explore the powerful features of PHPFlasher{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 mb-12">
|
||||
<div class="bg-white rounded-lg shadow-md overflow-hidden hover:shadow-lg transition duration-300">
|
||||
<div class="bg-indigo-600 h-2"></div>
|
||||
<div class="p-6">
|
||||
<div class="flex items-center space-x-3 mb-3">
|
||||
<div class="bg-indigo-100 p-2 rounded-md">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 text-indigo-600" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<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" />
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="text-xl font-bold text-gray-800">Notification Types</h3>
|
||||
</div>
|
||||
<p class="text-gray-600">Display success, error, warning, and info notifications to communicate different messages to your users.</p>
|
||||
<div class="mt-4">
|
||||
<a href="{{ path('app_types') }}" class="text-indigo-600 hover:text-indigo-800 font-medium">See Notification Types →</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-white rounded-lg shadow-md overflow-hidden hover:shadow-lg transition duration-300">
|
||||
<div class="bg-emerald-600 h-2"></div>
|
||||
<div class="p-6">
|
||||
<div class="flex items-center space-x-3 mb-3">
|
||||
<div class="bg-emerald-100 p-2 rounded-md">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 text-emerald-600" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 20l-5.447-2.724A1 1 0 013 16.382V5.618a1 1 0 011.447-.894L9 7m0 13l6-3m-6 3V7m6 10l4.553 2.276A1 1 0 0021 18.382V7.618a1 1 0 00-.553-.894L15 4m0 13V4" />
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="text-xl font-bold text-gray-800">Notification Positions</h3>
|
||||
</div>
|
||||
<p class="text-gray-600">Place notifications in different positions around the screen to best suit your UI design.</p>
|
||||
<div class="mt-4">
|
||||
<a href="{{ path('app_positions') }}" class="text-emerald-600 hover:text-emerald-800 font-medium">Explore Positions →</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-white rounded-lg shadow-md overflow-hidden hover:shadow-lg transition duration-300">
|
||||
<div class="bg-amber-500 h-2"></div>
|
||||
<div class="p-6">
|
||||
<div class="flex items-center space-x-3 mb-3">
|
||||
<div class="bg-amber-100 p-2 rounded-md">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 text-amber-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<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 stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="text-xl font-bold text-gray-800">Configuration Options</h3>
|
||||
</div>
|
||||
<p class="text-gray-600">Customize timeouts, animations, progressbars, and more with PHPFlasher's flexible configuration.</p>
|
||||
<div class="mt-4">
|
||||
<a href="{{ path('app_options') }}" class="text-amber-600 hover:text-amber-800 font-medium">View Options →</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-8 mb-12">
|
||||
<div class="bg-white rounded-lg shadow-md overflow-hidden">
|
||||
<div class="p-6">
|
||||
<h3 class="text-xl font-bold mb-4 text-gray-800">Plugins & Extensions</h3>
|
||||
<p class="text-gray-600 mb-4">PHPFlasher can be extended with plugins to add more functionality.</p>
|
||||
<div class="flex justify-end">
|
||||
<a href="{{ path('app_plugins') }}" class="btn btn-primary">Explore Plugins</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-white rounded-lg shadow-md overflow-hidden">
|
||||
<div class="p-6">
|
||||
<h3 class="text-xl font-bold mb-4 text-gray-800">Notification Presets</h3>
|
||||
<p class="text-gray-600 mb-4">Create reusable notification configurations for consistent messaging.</p>
|
||||
<div class="flex justify-end">
|
||||
<a href="{{ path('app_presets') }}" class="btn btn-primary">View Presets</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-indigo-50 rounded-lg p-8 mb-12">
|
||||
<div class="text-center">
|
||||
<h2 class="text-2xl font-bold text-indigo-800 mb-4">Try Out the Interactive Playground</h2>
|
||||
<p class="text-indigo-600 mb-6 max-w-2xl mx-auto">Want to experiment with different notification settings? Use our interactive playground to test PHPFlasher's features in real-time.</p>
|
||||
<div class="flex justify-center">
|
||||
<a href="{{ path('app_playground') }}" class="btn btn-primary">Go to Playground</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
@@ -0,0 +1,302 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block title %}PHPFlasher - Themes{% endblock %}
|
||||
|
||||
{% block page_title %}PHPFlasher Themes{% endblock %}
|
||||
{% block page_subtitle %}Beautiful notification themes to match your application's design{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="bg-white rounded-lg shadow-md overflow-hidden mb-8">
|
||||
<div class="p-6">
|
||||
<h2 class="text-xl font-bold mb-4">Available Themes</h2>
|
||||
<p class="text-gray-600 mb-6">
|
||||
PHPFlasher comes with various themes to help you match the notification style to your application's design.
|
||||
Each theme provides a distinct visual appearance while maintaining the same functionality.
|
||||
</p>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 mb-8">
|
||||
<div class="theme-card">
|
||||
<div class="bg-indigo-600 h-2"></div>
|
||||
<div class="theme-preview bg-indigo-50 flex items-center justify-center p-4">
|
||||
<div class="w-full bg-white rounded-lg shadow-md p-4">
|
||||
<div class="flex">
|
||||
<div class="flex-shrink-0">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-indigo-500" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
</div>
|
||||
<div class="ml-3">
|
||||
<p class="text-sm font-medium text-gray-900">Flasher Default Theme</p>
|
||||
<p class="text-xs text-gray-500">Clean and minimal design</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-4">
|
||||
<h3 class="text-lg font-semibold mb-2">Flasher (Default)</h3>
|
||||
<p class="text-gray-600 text-sm mb-4">The default theme with a clean, minimal design that works well in most applications.</p>
|
||||
<button class="w-full btn btn-primary theme-demo" data-theme="flasher">
|
||||
Preview Theme
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="theme-card">
|
||||
<div class="bg-emerald-600 h-2"></div>
|
||||
<div class="theme-preview bg-emerald-50 flex items-center justify-center p-4">
|
||||
<div class="w-full bg-white rounded-lg shadow-md p-4 border-l-4 border-emerald-500">
|
||||
<div class="flex">
|
||||
<div class="ml-3">
|
||||
<p class="text-sm font-medium text-gray-900">Emerald Theme</p>
|
||||
<p class="text-xs text-gray-500">Elegant left-border style</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-4">
|
||||
<h3 class="text-lg font-semibold mb-2">Emerald</h3>
|
||||
<p class="text-gray-600 text-sm mb-4">A sleek theme with colored left borders and subtle design elements.</p>
|
||||
<button class="w-full btn btn-primary theme-demo" data-theme="emerald">
|
||||
Preview Theme
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="theme-card">
|
||||
<div class="bg-blue-600 h-2"></div>
|
||||
<div class="theme-preview bg-blue-50 flex items-center justify-center p-4">
|
||||
<div class="w-full bg-white rounded-lg shadow-md p-4">
|
||||
<div class="flex">
|
||||
<div class="flex-shrink-0 bg-blue-100 rounded-full p-1">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-blue-500" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2h-1V9a1 1 0 00-1-1z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
</div>
|
||||
<div class="ml-3">
|
||||
<p class="text-sm font-medium text-gray-900">Sapphire Theme</p>
|
||||
<p class="text-xs text-gray-500">Modern with rounded icons</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-4">
|
||||
<h3 class="text-lg font-semibold mb-2">Sapphire</h3>
|
||||
<p class="text-gray-600 text-sm mb-4">A modern theme with rounded icons and smooth animations.</p>
|
||||
<button class="w-full btn btn-primary theme-demo" data-theme="sapphire">
|
||||
Preview Theme
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="theme-card">
|
||||
<div class="bg-purple-600 h-2"></div>
|
||||
<div class="theme-preview bg-purple-50 flex items-center justify-center p-4">
|
||||
<div class="w-full bg-white rounded-lg shadow-md p-4 bg-opacity-80 backdrop-filter backdrop-blur-sm">
|
||||
<div class="flex">
|
||||
<div class="flex-shrink-0">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-purple-500" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path d="M2 10.5a1.5 1.5 0 113 0v6a1.5 1.5 0 01-3 0v-6zM6 10.333v5.43a2 2 0 001.106 1.79l.05.025A4 4 0 008.943 18h5.416a2 2 0 001.962-1.608l1.2-6A2 2 0 0015.56 8H12V4a2 2 0 00-2-2 1 1 0 00-1 1v.667a4 4 0 01-.8 2.4L6.8 7.933a4 4 0 00-.8 2.4z" />
|
||||
</svg>
|
||||
</div>
|
||||
<div class="ml-3">
|
||||
<p class="text-sm font-medium text-gray-900">Crystal Theme</p>
|
||||
<p class="text-xs text-gray-500">Transparent with blur effects</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-4">
|
||||
<h3 class="text-lg font-semibold mb-2">Crystal</h3>
|
||||
<p class="text-gray-600 text-sm mb-4">A modern glass-like theme with transparency and blur effects.</p>
|
||||
<button class="w-full btn btn-primary theme-demo" data-theme="crystal">
|
||||
Preview Theme
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="theme-card">
|
||||
<div class="bg-amber-500 h-2"></div>
|
||||
<div class="theme-preview bg-amber-50 flex items-center justify-center p-4">
|
||||
<div class="w-full bg-white rounded-lg shadow-md p-4">
|
||||
<div class="flex">
|
||||
<div class="flex-shrink-0 bg-amber-100 p-1 rounded">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-amber-500" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path fill-rule="evenodd" d="M18 3a1 1 0 00-1.447-.894L8.763 6H5a3 3 0 000 6h.28l1.771 5.316A1 1 0 008 18h1a1 1 0 001-1v-4.382l6.553 3.276A1 1 0 0018 15V3z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
</div>
|
||||
<div class="ml-3">
|
||||
<p class="text-sm font-medium text-gray-900">Amazon Theme</p>
|
||||
<p class="text-xs text-gray-500">Inspired by Amazon's notification style</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-4">
|
||||
<h3 class="text-lg font-semibold mb-2">Amazon</h3>
|
||||
<p class="text-gray-600 text-sm mb-4">Inspired by Amazon's notification style with distinctive icons.</p>
|
||||
<button class="w-full btn btn-primary theme-demo" data-theme="amazon">
|
||||
Preview Theme
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-white rounded-lg shadow-md overflow-hidden mb-8">
|
||||
<div class="p-6">
|
||||
<h2 class="text-xl font-bold mb-4">Using Themes in Your Code</h2>
|
||||
<p class="text-gray-600 mb-4">
|
||||
You can specify which theme to use for each notification using the <code>option()</code> method:
|
||||
</p>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>PHP</span>
|
||||
</div>
|
||||
<pre><code class="language-php">// Using the default theme
|
||||
flash()->success('Your profile has been updated successfully!');
|
||||
|
||||
// Using the Emerald theme
|
||||
flash()->option('theme', 'emerald')
|
||||
->success('Your profile has been updated successfully!');
|
||||
|
||||
// Using the Sapphire theme with additional options
|
||||
flash()->option('theme', 'sapphire')
|
||||
->option('position', 'bottom-right')
|
||||
->option('timeout', 5000)
|
||||
->info('You have 3 unread messages.');
|
||||
|
||||
// Using the Amazon theme
|
||||
flash()->option('theme', 'amazon')
|
||||
->warning('Your subscription will expire in 3 days.');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-white rounded-lg shadow-md overflow-hidden mb-8">
|
||||
<div class="p-6">
|
||||
<h2 class="text-xl font-bold mb-4">Theme Configuration</h2>
|
||||
<p class="text-gray-600 mb-4">
|
||||
You can configure themes globally in your configuration file:
|
||||
</p>
|
||||
|
||||
<div class="code-block mb-6">
|
||||
<div class="code-header">
|
||||
<span>YAML</span>
|
||||
</div>
|
||||
<pre><code class="language-yaml"># config/packages/flasher.yaml
|
||||
flasher:
|
||||
# Set the default theme for all notifications
|
||||
default: theme.amazon
|
||||
|
||||
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
|
||||
|
||||
emerald:
|
||||
scripts:
|
||||
- '/vendor/flasher/themes/emerald/emerald.min.js'
|
||||
styles:
|
||||
- '/vendor/flasher/flasher.min.css'
|
||||
- '/vendor/flasher/themes/emerald/emerald.min.css'
|
||||
options:
|
||||
position: 'top-right'
|
||||
timeout: 5000</code></pre>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 mb-4">
|
||||
Each theme can have its own default options, scripts, and styles. This allows you to create a consistent notification experience throughout your application.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-white rounded-lg shadow-md overflow-hidden">
|
||||
<div class="p-6">
|
||||
<h2 class="text-xl font-bold mb-4">Custom Theme Templates</h2>
|
||||
<p class="text-gray-600 mb-4">
|
||||
Need something more customized? PHPFlasher allows you to create your own themes:
|
||||
</p>
|
||||
|
||||
<div class="code-block mb-6">
|
||||
<div class="code-header">
|
||||
<span>YAML</span>
|
||||
</div>
|
||||
<pre><code class="language-yaml"># config/packages/flasher.yaml
|
||||
flasher:
|
||||
themes:
|
||||
custom_theme:
|
||||
scripts:
|
||||
- '/assets/js/custom-theme.js'
|
||||
styles:
|
||||
- '/assets/css/custom-theme.css'
|
||||
options:
|
||||
position: 'top-center'
|
||||
timeout: 7000
|
||||
# Add any custom options your theme supports</code></pre>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 mb-4">
|
||||
Then you can use your custom theme in your code:
|
||||
</p>
|
||||
|
||||
<div class="code-block mb-6">
|
||||
<div class="code-header">
|
||||
<span>PHP</span>
|
||||
</div>
|
||||
<pre><code class="language-php">flash()->option('theme', 'custom_theme')
|
||||
->success('This uses your custom theme!');</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-center">
|
||||
<a href="{{ path('app_theme_builder') }}" class="btn btn-primary">
|
||||
Try the Theme Builder
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block javascripts %}
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const themeButtons = document.querySelectorAll('.theme-demo');
|
||||
|
||||
themeButtons.forEach(button => {
|
||||
button.addEventListener('click', function() {
|
||||
const theme = this.getAttribute('data-theme');
|
||||
const messages = {
|
||||
'flasher': 'This notification uses the Flasher theme!',
|
||||
'emerald': 'This notification uses the Emerald theme!',
|
||||
'sapphire': 'This notification uses the Sapphire theme!',
|
||||
'crystal': 'This notification uses the Crystal theme!',
|
||||
'amazon': 'This notification uses the Amazon theme!'
|
||||
};
|
||||
|
||||
// Send AJAX request to show notification
|
||||
fetch('{{ path('app_show_notification') }}', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Requested-With': 'XMLHttpRequest'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
type: 'success',
|
||||
message: messages[theme] || 'Theme preview',
|
||||
options: {
|
||||
theme: theme
|
||||
}
|
||||
})
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,8 @@
|
||||
# This file is used by TailwindCSS and browserslist to determine
|
||||
# which browsers to support with generated CSS
|
||||
|
||||
# Define target browsers
|
||||
last 2 versions
|
||||
not dead
|
||||
> 0.5%
|
||||
Firefox ESR
|
||||
+3
-2
@@ -5,11 +5,12 @@ gem 'csv'
|
||||
gem 'bigdecimal'
|
||||
gem 'base64'
|
||||
gem 'kramdown-parser-gfm'
|
||||
gem "webrick"
|
||||
gem "logger"
|
||||
|
||||
group :jekyll_plugins do
|
||||
gem 'jekyll-sitemap'
|
||||
gem 'jekyll-redirect-from'
|
||||
gem 'jekyll-seo-tag'
|
||||
gem 'jekyll-paginate'
|
||||
end
|
||||
|
||||
gem "webrick"
|
||||
|
||||
+31
-23
@@ -43,34 +43,39 @@ GEM
|
||||
bigdecimal
|
||||
rake (>= 13)
|
||||
http_parser.rb (0.8.0)
|
||||
i18n (1.14.6)
|
||||
i18n (1.14.7)
|
||||
concurrent-ruby (~> 1.0)
|
||||
jekyll (4.3.4)
|
||||
jekyll (4.4.1)
|
||||
addressable (~> 2.4)
|
||||
base64 (~> 0.2)
|
||||
colorator (~> 1.0)
|
||||
csv (~> 3.0)
|
||||
em-websocket (~> 0.5)
|
||||
i18n (~> 1.0)
|
||||
jekyll-sass-converter (>= 2.0, < 4.0)
|
||||
jekyll-watch (~> 2.0)
|
||||
json (~> 2.6)
|
||||
kramdown (~> 2.3, >= 2.3.1)
|
||||
kramdown-parser-gfm (~> 1.0)
|
||||
liquid (~> 4.0)
|
||||
mercenary (>= 0.3.6, < 0.5)
|
||||
mercenary (~> 0.3, >= 0.3.6)
|
||||
pathutil (~> 0.9)
|
||||
rouge (>= 3.0, < 5.0)
|
||||
safe_yaml (~> 1.0)
|
||||
terminal-table (>= 1.8, < 4.0)
|
||||
webrick (~> 1.7)
|
||||
jekyll-paginate (1.1.0)
|
||||
jekyll-redirect-from (0.16.0)
|
||||
jekyll (>= 3.3, < 5.0)
|
||||
jekyll-sass-converter (3.0.0)
|
||||
sass-embedded (~> 1.54)
|
||||
jekyll-sass-converter (3.1.0)
|
||||
sass-embedded (~> 1.75)
|
||||
jekyll-seo-tag (2.8.0)
|
||||
jekyll (>= 3.8, < 5.0)
|
||||
jekyll-sitemap (1.4.0)
|
||||
jekyll (>= 3.7, < 5.0)
|
||||
jekyll-watch (2.2.1)
|
||||
listen (~> 3.0)
|
||||
json (2.10.1)
|
||||
kramdown (2.5.1)
|
||||
rexml (>= 3.3.9)
|
||||
kramdown-parser-gfm (1.1.0)
|
||||
@@ -79,6 +84,7 @@ GEM
|
||||
listen (3.9.0)
|
||||
rb-fsevent (~> 0.10, >= 0.10.3)
|
||||
rb-inotify (~> 0.9, >= 0.9.10)
|
||||
logger (1.6.6)
|
||||
mercenary (0.4.0)
|
||||
pathutil (0.16.2)
|
||||
forwardable-extended (~> 2.6)
|
||||
@@ -87,43 +93,43 @@ GEM
|
||||
rb-fsevent (0.11.2)
|
||||
rb-inotify (0.11.1)
|
||||
ffi (~> 1.0)
|
||||
rexml (3.4.0)
|
||||
rexml (3.4.1)
|
||||
rouge (4.5.1)
|
||||
safe_yaml (1.0.5)
|
||||
sass-embedded (1.83.4)
|
||||
sass-embedded (1.85.0)
|
||||
google-protobuf (~> 4.29)
|
||||
rake (>= 13)
|
||||
sass-embedded (1.83.4-aarch64-linux-android)
|
||||
sass-embedded (1.85.0-aarch64-linux-android)
|
||||
google-protobuf (~> 4.29)
|
||||
sass-embedded (1.83.4-aarch64-linux-gnu)
|
||||
sass-embedded (1.85.0-aarch64-linux-gnu)
|
||||
google-protobuf (~> 4.29)
|
||||
sass-embedded (1.83.4-aarch64-linux-musl)
|
||||
sass-embedded (1.85.0-aarch64-linux-musl)
|
||||
google-protobuf (~> 4.29)
|
||||
sass-embedded (1.83.4-aarch64-mingw-ucrt)
|
||||
sass-embedded (1.85.0-aarch64-mingw-ucrt)
|
||||
google-protobuf (~> 4.29)
|
||||
sass-embedded (1.83.4-arm-linux-androideabi)
|
||||
sass-embedded (1.85.0-arm-linux-androideabi)
|
||||
google-protobuf (~> 4.29)
|
||||
sass-embedded (1.83.4-arm-linux-gnueabihf)
|
||||
sass-embedded (1.85.0-arm-linux-gnueabihf)
|
||||
google-protobuf (~> 4.29)
|
||||
sass-embedded (1.83.4-arm-linux-musleabihf)
|
||||
sass-embedded (1.85.0-arm-linux-musleabihf)
|
||||
google-protobuf (~> 4.29)
|
||||
sass-embedded (1.83.4-arm64-darwin)
|
||||
sass-embedded (1.85.0-arm64-darwin)
|
||||
google-protobuf (~> 4.29)
|
||||
sass-embedded (1.83.4-riscv64-linux-android)
|
||||
sass-embedded (1.85.0-riscv64-linux-android)
|
||||
google-protobuf (~> 4.29)
|
||||
sass-embedded (1.83.4-riscv64-linux-gnu)
|
||||
sass-embedded (1.85.0-riscv64-linux-gnu)
|
||||
google-protobuf (~> 4.29)
|
||||
sass-embedded (1.83.4-riscv64-linux-musl)
|
||||
sass-embedded (1.85.0-riscv64-linux-musl)
|
||||
google-protobuf (~> 4.29)
|
||||
sass-embedded (1.83.4-x86_64-cygwin)
|
||||
sass-embedded (1.85.0-x86_64-cygwin)
|
||||
google-protobuf (~> 4.29)
|
||||
sass-embedded (1.83.4-x86_64-darwin)
|
||||
sass-embedded (1.85.0-x86_64-darwin)
|
||||
google-protobuf (~> 4.29)
|
||||
sass-embedded (1.83.4-x86_64-linux-android)
|
||||
sass-embedded (1.85.0-x86_64-linux-android)
|
||||
google-protobuf (~> 4.29)
|
||||
sass-embedded (1.83.4-x86_64-linux-gnu)
|
||||
sass-embedded (1.85.0-x86_64-linux-gnu)
|
||||
google-protobuf (~> 4.29)
|
||||
sass-embedded (1.83.4-x86_64-linux-musl)
|
||||
sass-embedded (1.85.0-x86_64-linux-musl)
|
||||
google-protobuf (~> 4.29)
|
||||
terminal-table (3.0.2)
|
||||
unicode-display_width (>= 1.1.1, < 3)
|
||||
@@ -161,10 +167,12 @@ DEPENDENCIES
|
||||
bigdecimal
|
||||
csv
|
||||
jekyll
|
||||
jekyll-paginate
|
||||
jekyll-redirect-from
|
||||
jekyll-seo-tag
|
||||
jekyll-sitemap
|
||||
kramdown-parser-gfm
|
||||
logger
|
||||
webrick
|
||||
|
||||
BUNDLED WITH
|
||||
|
||||
+16
-2
@@ -7,7 +7,7 @@ logo: https://php-flasher.io/static/images/php-flasher-social-card.png
|
||||
author:
|
||||
name: Younes ENNAJI
|
||||
twitter: yoeunes
|
||||
url: https://www.linkedin.com/in/younes--ennaji/
|
||||
url: https://www.linkedin.com/in/yoeunes/
|
||||
picture: https://php-flasher.io/static/images/php-flasher-social-card.png
|
||||
|
||||
image:
|
||||
@@ -26,7 +26,7 @@ social:
|
||||
- https://github.com/php-flasher
|
||||
- https://twitter.com/yoeunes
|
||||
- https://github.com/yoeunes
|
||||
- https://www.linkedin.com/in/younes--ennaji/
|
||||
- https://www.linkedin.com/in/yoeunes/
|
||||
|
||||
highlighter: none
|
||||
|
||||
@@ -34,6 +34,15 @@ plugins:
|
||||
- jekyll-sitemap
|
||||
- jekyll-redirect-from
|
||||
- jekyll-seo-tag
|
||||
- jekyll-paginate
|
||||
|
||||
permalink: /blog/:year/:month/:day/:title/
|
||||
paginate: 10
|
||||
paginate_path: "/blog/page:num/"
|
||||
|
||||
collections:
|
||||
posts:
|
||||
output: true
|
||||
|
||||
defaults:
|
||||
- scope:
|
||||
@@ -46,6 +55,11 @@ defaults:
|
||||
image: https://php-flasher.io/static/images/php-flasher-social-card.png
|
||||
published_at: "2019-12-01"
|
||||
updated_at: "2024-03-29"
|
||||
- scope:
|
||||
path: ""
|
||||
type: "posts"
|
||||
values:
|
||||
layout: "post"
|
||||
|
||||
exclude:
|
||||
- "*.config.js"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"dist/main.css": "/dist/main.801e5ea3.css",
|
||||
"dist/main.js": "/dist/main.36e31cce.js",
|
||||
"dist/main.css": "/dist/main.b2cdcaf6.css",
|
||||
"dist/main.js": "/dist/main.29f69f71.js",
|
||||
"dist/455.3a7b4474.css": "/dist/455.3a7b4474.css",
|
||||
"dist/455.095e6545.js": "/dist/455.095e6545.js",
|
||||
"dist/411.29cd993e.css": "/dist/411.29cd993e.css",
|
||||
|
||||
+21
-1
@@ -1,12 +1,32 @@
|
||||
<i class="fa-duotone fa-rocket"></i> Getting Started:
|
||||
<i class="fa-duotone fa-book text-indigo-900 mr-1 fa-lg"></i> Introduction: '/'
|
||||
<i class="fa-duotone fa-flask text-purple-600 mr-1 fa-lg"></i> Playground: '/playground/'
|
||||
<i class="fa-brands fa-symfony fa-lg text-black mr-1"></i> Symfony: '/symfony/'
|
||||
<i class="fa-brands fa-laravel fa-lg text-red-900 mr-1"></i> Laravel: '/laravel/'
|
||||
<i class="fa-duotone fa-ghost fa-lg text-pink-800 mr-1"></i> Livewire: '/livewire/'
|
||||
<i class="fa-duotone fa-angles-right fa-lg text-indigo-900 mr-1"></i> Inertia: '/inertia/'
|
||||
|
||||
<i class="fa-duotone fa-plug"></i> libraries:
|
||||
<i class="fa-duotone fa-plug"></i> 3rd Party:
|
||||
<i class="fa-duotone fa-bell text-indigo-900 mr-1 fa-lg"></i> Noty: '/library/noty/'
|
||||
<i class="fa-duotone fa-info-circle text-indigo-900 mr-1 fa-lg"></i> Notyf: '/library/notyf/'
|
||||
<i class="fa-duotone fa-exclamation-circle text-indigo-900 mr-1 fa-lg"></i> Sweetalert: '/library/sweetalert/'
|
||||
<i class="fa-duotone fa-bread-loaf text-indigo-900 mr-1 fa-lg"></i> Toastr: '/library/toastr/'
|
||||
|
||||
<i class="fa-duotone fa-palette"></i> Themes <span class="text-xs bg-indigo-500 text-white px-2 py-0.5 rounded-full font-medium ml-1">NEW</span>:
|
||||
<i class="fa-duotone fa-th-large text-indigo-600 mr-1 fa-lg"></i> All Themes: '/themes/'
|
||||
<i class="fa-duotone fa-circle-minus text-indigo-900 mr-1 fa-lg"></i> Minimal: '/theme/minimal/'
|
||||
<i class="fa-duotone fa-sun text-yellow-600 mr-1 fa-lg"></i> Amber: '/theme/amber/'
|
||||
<i class="fa-duotone fa-diamond text-indigo-900 mr-1 fa-lg"></i> Crystal: '/theme/crystal/'
|
||||
<i class="fa-duotone fa-lightbulb text-yellow-300 mr-1 fa-lg"></i> Neon: '/theme/neon/'
|
||||
<i class="fa-duotone fa-gem text-purple-800 mr-1 fa-lg"></i> Onyx: '/theme/onyx/'
|
||||
<i class="fa-duotone fa-gem text-green-500 mr-1 fa-lg"></i> Emerald: '/theme/emerald/'
|
||||
<i class="fa-duotone fa-leaf text-green-600 mr-1 fa-lg"></i> Jade: '/theme/jade/'
|
||||
<i class="fa-duotone fa-sparkles text-blue-400 mr-1 fa-lg"></i> Aurora: '/theme/aurora/'
|
||||
<i class="fa-duotone fa-gem text-red-600 mr-1 fa-lg"></i> Ruby: '/theme/ruby/'
|
||||
<i class="fa-duotone fa-gem text-blue-500 mr-1 fa-lg"></i> Sapphire: '/theme/sapphire/'
|
||||
<i class="fa-duotone fa-layer-group text-indigo-900 mr-1 fa-lg"></i> Material: '/theme/material/'
|
||||
<i class="fa-brands fa-google text-red-500 mr-1 fa-lg"></i> Google: '/theme/google/'
|
||||
<i class="fa-duotone fa-shopping-bag text-indigo-900 mr-1 fa-lg"></i> Amazon: '/theme/amazon/'
|
||||
<i class="fa-brands fa-facebook text-blue-600 mr-1 fa-lg"></i> Facebook: '/theme/facebook/'
|
||||
<i class="fa-brands fa-apple text-gray-800 mr-1 fa-lg"></i> IOS: '/theme/ios/'
|
||||
<i class="fa-brands fa-slack text-purple-500 mr-1 fa-lg"></i> Slack: '/theme/slack/'
|
||||
|
||||
@@ -6,4 +6,3 @@ description: "PHPFlasher - A powerful & easy-to-use package for adding flash mes
|
||||
|
||||
versions:
|
||||
2.x: "https://php-flasher.io/"
|
||||
1.x: "https://php-flasher.github.io/"
|
||||
|
||||
+26
-37
@@ -1,6 +1,6 @@
|
||||
## <i class="fa-duotone fa-list-radio"></i> Usage
|
||||
|
||||
To show a notification message, you can use the `flash()` helper function or get an instance of `flasher` from the service container. Before you return a view or redirect, call one of the notification methods like `success()` and pass in the message you want to display.
|
||||
<strong><span class="text-indigo-900">PHP<span class="text-indigo-500">Flasher</span></span></strong> provides a simple and intuitive way to add notifications to your application. You can use either the `flash()` helper function or inject the `FlasherInterface` through dependency injection.
|
||||
|
||||
{% assign id = '#/ PHPFlasher' %}
|
||||
{% assign type = 'success' %}
|
||||
@@ -11,40 +11,29 @@ To show a notification message, you can use the `flash()` helper function or get
|
||||
```php
|
||||
{{ id }}
|
||||
|
||||
// Using the helper function
|
||||
flash()->success('{{ site.data.messages["success"] | sample }}');
|
||||
|
||||
// Or using dependency injection
|
||||
use Flasher\Prime\FlasherInterface;
|
||||
|
||||
class BookController
|
||||
{
|
||||
public function saveBook()
|
||||
public function store(FlasherInterface $flasher)
|
||||
{
|
||||
// ...
|
||||
|
||||
flash()->success('{{ site.data.messages["success"] | sample }}');
|
||||
|
||||
flash('{{ message }}');
|
||||
|
||||
// ... redirect or render a view
|
||||
}
|
||||
|
||||
/**
|
||||
* if you prefer to use dependency injection
|
||||
*/
|
||||
public function register(FlasherInterface $flasher)
|
||||
{
|
||||
// ...
|
||||
|
||||
$flasher->success('{{ site.data.messages["success"] | sample }}');
|
||||
|
||||
// ... redirect or render a view
|
||||
// Save the book...
|
||||
$flasher->success('{{ message }}');
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<br />
|
||||
|
||||
Choose a message that is clear and tells the user what happened. For example, `"Book has been created successfully!"` is a good message, but you can adjust it to fit your application's context and language.
|
||||
Choose a clear message that tells the user what happened. For example, `"Book has been created successfully!"` is a good message, but you can adjust it to fit your application's context and language.
|
||||
|
||||
> Using this package is easy. You can add notifications to your application with just one line of code.
|
||||
> This package is easy to use. You can add notifications to your application with just one line of code.
|
||||
|
||||
{% assign id = '#/ usage success' %}
|
||||
{% assign type = 'success' %}
|
||||
@@ -178,7 +167,7 @@ flash()
|
||||
|
||||
<p id="method-priority"><a href="#method-priority" class="anchor"><i class="fa-duotone fa-link"></i> priority</a></p>
|
||||
|
||||
Set the priority of a flash message. Messages with higher priority appear first.
|
||||
Control the order of multiple notifications, messages with higher priority appear first.
|
||||
|
||||
```php
|
||||
flash()->priority(int $priority);
|
||||
@@ -191,29 +180,29 @@ flash()->priority(int $priority);
|
||||
{% assign infoMessage = site.data.messages['info'] | sample | prepend: 'Priority 2 → ' %}
|
||||
|
||||
<script type="text/javascript">
|
||||
messages["{{ id }}"] = [
|
||||
messages['{{ id }}'] = [
|
||||
{
|
||||
handler: "flasher",
|
||||
type: "warning",
|
||||
message: "{{ warningMessage }}",
|
||||
handler: 'flasher',
|
||||
type: 'warning',
|
||||
message: '{{ warningMessage }}',
|
||||
options: {},
|
||||
},
|
||||
{
|
||||
handler: "flasher",
|
||||
type: "success",
|
||||
message: "{{ successMessage }}",
|
||||
handler: 'flasher',
|
||||
type: 'success',
|
||||
message: '{{ successMessage }}',
|
||||
options: {},
|
||||
},
|
||||
{
|
||||
handler: "flasher",
|
||||
type: "info",
|
||||
message: "{{ infoMessage }}",
|
||||
handler: 'flasher',
|
||||
type: 'info',
|
||||
message: '{{ infoMessage }}',
|
||||
options: {},
|
||||
},
|
||||
{
|
||||
handler: "flasher",
|
||||
type: "error",
|
||||
message: "{{ errorMessage }}",
|
||||
handler: 'flasher',
|
||||
type: 'error',
|
||||
message: '{{ errorMessage }}',
|
||||
options: {},
|
||||
},
|
||||
];
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
<div class="bg-green-700 text-white text-center p-1.5 leading-tight shadow-lg relative overflow-hidden">
|
||||
<div class="absolute inset-0 bg-gradient-to-r from-green-800 to-green-600 opacity-50"></div>
|
||||
<div class="container mx-auto px-4 relative z-10">
|
||||
<span class="text-xl font-bold"><img src="/static/images/palestine-flag.png" alt="Palestinian Flag" class="inline h-4 w-auto mr-1"> Solidarity with Palestine.</span>
|
||||
<span class="inline text-xs sm:text-sm md:text-base ml-1">We seek justice and peace, and strongly oppose all forms of injustice and genocide.</span>
|
||||
</div>
|
||||
</div>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user