Compare commits

...

265 Commits

Author SHA1 Message Date
Younes ENNAJI 18663b3214 Updates Flasher to v2.2.0
Updates the flasher dependencies in composer.json files and package.json files to version 2.2.0.

Updates the Flasher version constant in the Prime Flasher class.
2025-11-10 15:20:21 +01:00
Younes ENNAJI 7cf3de856e Merge pull request #286 from php-flasher/dev
add phpflasher configuration article
2025-03-30 07:41:23 +00:00
Younes ENNAJI e0cbc53c76 add phpflasher configuration article 2025-03-30 07:39:24 +00:00
Younes ENNAJI b5bf2325be Merge pull request #285 from php-flasher/dev
add common phpflasher implementation mistakes blog post
2025-03-30 07:18:22 +00:00
Younes ENNAJI e3158290f3 add common phpflasher implementation mistakes blog post 2025-03-30 07:15:03 +00:00
Younes ENNAJI 4070978256 Merge pull request #284 from php-flasher/dev
add blog section
2025-03-30 06:42:07 +00:00
Younes ENNAJI d96a953488 update blog icon 2025-03-30 06:39:58 +00:00
Younes ENNAJI ea8391eb6b update laravel first blog article 2025-03-30 06:03:55 +00:00
Younes ENNAJI 3fc0d83dd6 improve laravel first blog article 2025-03-30 05:22:04 +00:00
Younes ENNAJI 1cb12c819b add blog articles 2025-03-30 04:10:13 +00:00
Younes ENNAJI f9d79f4589 Merge pull request #283 from php-flasher/dev
update themes documentataion
2025-03-30 03:11:35 +00:00
Younes ENNAJI a3ce6a5262 update themes documentataion 2025-03-30 02:56:43 +00:00
Younes ENNAJI ff2cc1dc65 Merge pull request #282 from php-flasher/dev
update docs home page
2025-03-30 02:33:13 +00:00
Younes ENNAJI 2cef5b98b2 fix phpstan errors 2025-03-30 02:27:41 +00:00
Younes ENNAJI d7ecfb69a9 revert laravel install command 2025-03-30 02:24:57 +00:00
Younes ENNAJI 4909da7ba8 update docs home page 2025-03-30 02:22:45 +00:00
Younes ENNAJI f854ed4315 Wip 2025-03-28 13:05:26 +00:00
Younes ENNAJI 424617103f Wip 2025-03-28 03:37:07 +00:00
Younes ENNAJI 8dd56001db Wip 2025-03-28 03:30:26 +00:00
Younes ENNAJI e1ae7e215c update laravel intaller command 2025-03-28 03:11:45 +00:00
Younes ENNAJI 730c13c447 update laravel theme configuration 2025-03-28 02:16:33 +00:00
Younes ENNAJI 12b0842cdd update symfony and laravel demos 2025-03-28 02:06:37 +00:00
Younes ENNAJI 93ca18a67b add themes to symfony configuration 2025-03-27 21:23:53 +00:00
Younes ENNAJI 1022991877 upgrade dependencies 2025-03-27 20:06:59 +00:00
Younes ENNAJI 4345f2aa91 Merge pull request #280 from php-flasher/dev
update themes border radius
2025-03-27 02:13:45 +00:00
Younes ENNAJI 56dd1cea4c update themes border radius 2025-03-27 02:12:06 +00:00
Younes ENNAJI 315a54eb43 Merge pull request #279 from php-flasher/dev
update themes icon
2025-03-26 23:37:35 +00:00
Younes ENNAJI 82f2c69d65 update themes icon 2025-03-26 23:34:57 +00:00
Younes ENNAJI 91993e438b Merge pull request #278 from php-flasher/dev
fix flash notifications width
2025-03-26 23:08:16 +00:00
Younes ENNAJI 977c645c45 upgrade dependencies 2025-03-26 23:06:45 +00:00
Younes ENNAJI 7a083efea0 fix flash notifications width 2025-03-26 23:04:01 +00:00
Younes ENNAJI 5448e54f77 Merge pull request #277 from php-flasher/dev
update livewire and inertiajs documentation
2025-03-26 21:34:02 +00:00
Younes ENNAJI c92105377d update livewire and inertiajs documentation 2025-03-26 21:32:32 +00:00
Younes ENNAJI 5cf68f2e34 Merge pull request #276 from php-flasher/dev
update laravel documentation page
2025-03-26 04:18:09 +00:00
Younes ENNAJI 68d7bfadce upgrade dependencies 2025-03-26 04:16:45 +00:00
Younes ENNAJI ca6e75ba9d update laravel documentation page 2025-03-26 04:06:45 +00:00
Younes ENNAJI 3407e309da Merge pull request #275 from php-flasher/dev
upgrade dependencies
2025-03-26 02:24:27 +00:00
Younes ENNAJI dce23cc288 upgrade dependencies 2025-03-26 02:22:33 +00:00
Younes ENNAJI c1cc26379d Merge pull request #274 from php-flasher/dev
update symfony documentation page
2025-03-26 02:17:02 +00:00
Younes ENNAJI cc0658b3fe update symfony documentation page 2025-03-26 02:15:21 +00:00
Younes ENNAJI a2abd9455a upgrade dependencies 2025-03-23 20:39:06 +00:00
Younes ENNAJI 8d160a6659 Merge pull request #273 from php-flasher/dev
fix flasher rtl support
2025-03-23 14:57:02 +00:00
Younes ENNAJI 8e6f0e8c88 fix flasher rtl support 2025-03-23 14:54:56 +00:00
Younes ENNAJI 4471ae6135 Merge pull request #272 from php-flasher/dev
Wip
2025-03-23 14:17:48 +00:00
Younes ENNAJI 6d162c7f95 Wip 2025-03-23 14:16:10 +00:00
Younes ENNAJI 4f8e179fb8 Merge pull request #271 from php-flasher/dev
dev
2025-03-23 13:35:11 +00:00
Younes ENNAJI 53d7795292 fix flasher options 2025-03-23 13:31:29 +00:00
Younes ENNAJI eec4b88872 Wip 2025-03-22 20:06:30 +00:00
Younes ENNAJI 37ac39e2ec Merge pull request #270 from php-flasher/dev
upgrade dependencies
2025-03-19 00:33:38 +00:00
Younes ENNAJI ef05362467 upgrade dependencies 2025-03-19 00:26:48 +00:00
Younes ENNAJI 05229b0b42 Merge pull request #269 from php-flasher/dev
update inertiajs documentation page
2025-03-19 00:09:17 +00:00
Younes ENNAJI 28ca9d1370 update inertiajs documentation page 2025-03-19 00:07:22 +00:00
Younes ENNAJI 03c358ce44 Merge pull request #268 from php-flasher/dev
update livewire documentation page
2025-03-18 23:37:02 +00:00
Younes ENNAJI 0edf9cc711 update livewire documentation page 2025-03-18 23:35:22 +00:00
Younes ENNAJI 04685fad82 Merge pull request #267 from php-flasher/dev
update laravel documentation page
2025-03-18 22:57:11 +00:00
Younes ENNAJI 2bfc7ec5d4 update laravel documentation page 2025-03-18 22:55:25 +00:00
Younes ENNAJI 4ef7a12484 Merge pull request #266 from php-flasher/dev
update symfony doc page
2025-03-18 22:41:16 +00:00
Younes ENNAJI 4f09f06e07 update symfony implementation 2025-03-18 22:38:47 +00:00
Younes ENNAJI 00c8273272 Wip 2025-03-18 22:22:32 +00:00
Younes ENNAJI 2a7657b09c Wip 2025-03-18 22:20:10 +00:00
Younes ENNAJI 24d3c90752 Wip 2025-03-18 22:08:01 +00:00
Younes ENNAJI 5f4a8beaa3 Wip 2025-03-18 22:02:54 +00:00
Younes ENNAJI 70e08fc913 Wip 2025-03-18 21:56:52 +00:00
Younes ENNAJI f0a11e6600 Wip 2025-03-18 21:39:09 +00:00
Younes ENNAJI 66704f6368 Wip 2025-03-18 20:37:11 +00:00
Younes ENNAJI c18fbd1124 Wip 2025-03-17 05:56:34 +00:00
Younes ENNAJI 1899de104f Merge pull request #264 from php-flasher/2.x-dev
update docs
2025-03-17 04:54:51 +00:00
Younes ENNAJI cd3ef599e1 Wip 2025-03-17 04:53:19 +00:00
Younes ENNAJI eb537353c2 Wip 2025-03-17 04:48:54 +00:00
Younes ENNAJI 4b1b747abe Merge pull request #263 from php-flasher/2.x-dev
update the docs
2025-03-17 03:59:52 +00:00
Younes ENNAJI 56109d9ed0 Wip 2025-03-17 03:57:41 +00:00
Younes ENNAJI a80c04bb19 Merge pull request #262 from php-flasher/2.x-dev
update the docs
2025-03-17 03:38:39 +00:00
Younes ENNAJI cd2c28ff11 Wip 2025-03-17 03:37:53 +00:00
Younes ENNAJI 3c79064e8d Wip 2025-03-17 03:29:19 +00:00
Younes ENNAJI 1e87cf5380 Wip 2025-03-17 03:26:27 +00:00
Younes ENNAJI 6dbef1d819 Merge pull request #261 from php-flasher/2.x-dev
update the docs
2025-03-17 03:04:54 +00:00
Younes ENNAJI c03c28533b update the docs 2025-03-17 03:03:07 +00:00
Younes ENNAJI 59a2e502c8 Merge pull request #260 from php-flasher/2.x-dev
make sidebar scrollable
2025-03-16 01:44:50 +00:00
Younes ENNAJI 3cb6ea7ed7 make sidebar scrollable 2025-03-16 01:43:23 +00:00
Younes ENNAJI bb83f55711 Merge pull request #259 from php-flasher/2.x-dev
fix flasher studio select theme
2025-03-16 01:17:20 +00:00
Younes ENNAJI ffbb8e5053 Wip 2025-03-16 01:15:32 +00:00
Younes ENNAJI aa82f13e08 Wip 2025-03-16 01:01:56 +00:00
Younes ENNAJI e8cd7a4595 Merge pull request #258 from php-flasher/2.x-dev
update docs demo
2025-03-13 08:15:13 +00:00
Younes ENNAJI 568e3583b9 Wip 2025-03-13 08:13:26 +00:00
Younes ENNAJI 113e609b55 Wip 2025-03-13 07:41:10 +00:00
Younes ENNAJI edd684cd7c Wip 2025-03-13 07:09:14 +00:00
Younes ENNAJI 302de1f212 Wip 2025-03-13 06:26:03 +00:00
Younes ENNAJI d0bf147008 Wip 2025-03-13 06:20:41 +00:00
Younes ENNAJI 5d7145ff65 Wip 2025-03-13 06:05:44 +00:00
Younes ENNAJI 2faa760217 Wip 2025-03-13 05:39:10 +00:00
Younes ENNAJI eb0d0fbb6d Wip 2025-03-12 21:27:05 +00:00
Younes ENNAJI ccaab5b7e5 Wip 2025-03-12 00:17:23 +00:00
Younes ENNAJI 2ecfdef874 Wip 2025-03-12 00:17:01 +00:00
Younes ENNAJI 49e287f987 Wip 2025-03-11 23:56:12 +00:00
Younes ENNAJI 60c19498e3 Wip 2025-03-11 23:52:20 +00:00
Younes ENNAJI 9e59dc83fe Wip 2025-03-11 23:34:41 +00:00
Younes ENNAJI f39aaa7de5 Wip 2025-03-11 23:12:37 +00:00
Younes ENNAJI 68ae6dc9cb Wip 2025-03-11 22:47:45 +00:00
Younes ENNAJI 356672c634 Wip 2025-03-11 22:44:01 +00:00
Younes ENNAJI eff520316e Wip 2025-03-11 22:33:12 +00:00
Younes ENNAJI fa3012a711 Wip 2025-03-11 22:02:22 +00:00
Younes ENNAJI 27024721ea Merge pull request #257 from php-flasher/2.x-dev
2.x dev
2025-03-11 07:45:13 +00:00
Younes ENNAJI 50a8b334be Wip 2025-03-11 07:43:34 +00:00
Younes ENNAJI 402b443f17 Wip 2025-03-11 07:37:11 +00:00
Younes ENNAJI 220284a892 Wip 2025-03-11 07:27:52 +00:00
Younes ENNAJI 5d81a1f0f1 Wip 2025-03-11 07:23:15 +00:00
Younes ENNAJI 5b8e6c64ff Wip 2025-03-11 07:00:44 +00:00
Younes ENNAJI 4b2edce0e4 Wip 2025-03-11 06:55:49 +00:00
Younes ENNAJI ff32c639ed Wip 2025-03-11 06:48:42 +00:00
Younes ENNAJI bad7544cf8 Wip 2025-03-11 06:36:08 +00:00
Younes ENNAJI a05d72d945 Wip 2025-03-11 06:27:42 +00:00
Younes ENNAJI 4672332012 Wip 2025-03-11 06:19:57 +00:00
Younes ENNAJI b4682b462a Wip 2025-03-11 06:14:16 +00:00
Younes ENNAJI 6ea30eb6d4 Wip 2025-03-11 06:09:49 +00:00
Younes ENNAJI b451da2141 Wip 2025-03-11 06:04:59 +00:00
Younes ENNAJI b5517bedcf Wip 2025-03-11 06:02:25 +00:00
Younes ENNAJI f411c6e3cb Wip 2025-03-11 05:53:39 +00:00
Younes ENNAJI 5a769cffc8 Wip 2025-03-11 05:43:53 +00:00
Younes ENNAJI dae72342b4 Merge pull request #256 from php-flasher/2.x-dev
update the themes in the docs
2025-03-11 05:10:17 +00:00
Younes ENNAJI ea47e9043b update the themes in the docs 2025-03-11 05:07:01 +00:00
Younes ENNAJI 3b42b1a862 Merge pull request #255 from php-flasher/2.x-dev
improve themes docs
2025-03-10 04:29:14 +00:00
Younes ENNAJI e1d7ae94ee Wip 2025-03-10 04:23:31 +00:00
Younes ENNAJI 1945e03640 Wip 2025-03-10 04:16:03 +00:00
Younes ENNAJI 00eadbe207 Wip 2025-03-10 04:07:11 +00:00
Younes ENNAJI ee51cb775d Wip 2025-03-10 03:45:48 +00:00
Younes ENNAJI 0cf5e8f70d Wip 2025-03-10 03:43:57 +00:00
Younes ENNAJI 09d60d496b Wip 2025-03-10 03:31:51 +00:00
Younes ENNAJI b48d52d3bc Wip 2025-03-10 03:26:41 +00:00
Younes ENNAJI 9849c63d99 Wip 2025-03-10 03:23:41 +00:00
Younes ENNAJI e332c78512 Wip 2025-03-10 03:23:08 +00:00
Younes ENNAJI 0a148c10c2 Wip 2025-03-10 03:20:04 +00:00
Younes ENNAJI cf03403459 Wip 2025-03-10 03:10:30 +00:00
Younes ENNAJI a7491972e2 Wip 2025-03-10 02:58:26 +00:00
Younes ENNAJI 21c5cbd624 Wip 2025-03-10 02:18:48 +00:00
Younes ENNAJI 664c841e8d Wip 2025-03-10 02:07:34 +00:00
Younes ENNAJI 5f6837ea31 Merge pull request #254 from php-flasher/2.x-dev
add themes to the docs
2025-03-10 00:55:05 +00:00
Younes ENNAJI 88ae4cfc4c add themes to the docs 2025-03-10 00:54:37 +00:00
Younes ENNAJI 042b314784 Merge pull request #253 from php-flasher/2.x-dev
update docs
2025-03-09 22:43:17 +00:00
Younes ENNAJI a43cbd21ce compile assets 2025-03-09 22:41:44 +00:00
Younes ENNAJI 39ca7b3e83 update docs 2025-03-09 22:15:50 +00:00
Younes ENNAJI 9d0bf7dca7 update docs 2025-03-09 20:23:16 +00:00
Younes ENNAJI 8913b6e0e2 Merge pull request #252 from php-flasher/2.x-dev
docs: enhance code documentation with comprehensive PHPDoc comments
2025-03-09 07:58:24 +00:00
Younes ENNAJI 0631e5953e docs: enhance code documentation with comprehensive PHPDoc comments 2025-03-09 07:34:22 +00:00
Younes ENNAJI bdc7e85380 Update README.md 2025-03-08 22:44:33 +00:00
Younes ENNAJI be071be46b Merge pull request #251 from php-flasher/2.x-dev
improve rollup configuration
2025-03-08 18:13:32 +00:00
Younes ENNAJI b047c9016a improve rollup configuration 2025-03-08 18:05:43 +00:00
Younes ENNAJI 8fa6054ada improve package.json 2025-03-08 12:31:44 +00:00
Younes ENNAJI c062ae7cf5 Merge pull request #250 from php-flasher/themes
add themes doc pages
2025-03-08 12:04:37 +00:00
Younes ENNAJI 1c8b0bf081 add themes doc pages 2025-03-08 12:03:23 +00:00
Younes ENNAJI 5eddda90c5 Merge pull request #249 from php-flasher/themes
update symfony demo
2025-03-08 12:03:07 +00:00
Younes ENNAJI 46ed2f8468 update symfony demo 2025-03-08 12:02:07 +00:00
Younes ENNAJI ecabbee799 Merge pull request #248 from php-flasher/themes
compile assets
2025-03-08 12:01:41 +00:00
Younes ENNAJI 568421c66b compile assets 2025-03-08 12:01:13 +00:00
Younes ENNAJI ed4f6165c6 Merge pull request #247 from php-flasher/themes
refactor toastr plugin and improve code documentation
2025-03-08 12:00:19 +00:00
Younes ENNAJI 02f5fc0460 refactor toastr plugin and improve code documentation 2025-03-08 11:59:56 +00:00
Younes ENNAJI a9aedc1236 Merge pull request #246 from php-flasher/themes
refactor sweealert plugin and improve code documentation
2025-03-08 11:59:32 +00:00
Younes ENNAJI b4c9df4549 refactor sweealert plugin and improve code documentation 2025-03-08 11:59:01 +00:00
Younes ENNAJI 4d0b258ed7 Merge pull request #245 from php-flasher/themes
refactor notyf plugin and improve code documentation
2025-03-08 11:58:39 +00:00
Younes ENNAJI 71b21855c1 refactor notyf plugin and improve code documentation 2025-03-08 11:58:00 +00:00
Younes ENNAJI f43878571b Merge pull request #244 from php-flasher/themes
refactor noty plugin and improve code documentation
2025-03-08 11:57:27 +00:00
Younes ENNAJI fbe6238009 refactor noty plugin and improve code documentation 2025-03-08 11:56:48 +00:00
Younes ENNAJI 2ed68db245 Merge pull request #243 from php-flasher/themes
refactor assets and improve code documentation
2025-03-08 11:55:05 +00:00
Younes ENNAJI c81a99c755 refactor assets and improve code documentation 2025-03-08 11:54:29 +00:00
Younes ENNAJI 3563e195bc Merge pull request #242 from php-flasher/themes
add slack theme
2025-03-08 11:53:26 +00:00
Younes ENNAJI 47c7cd9ad8 add slack theme 2025-03-08 11:52:59 +00:00
Younes ENNAJI 6b9cf6b90c Merge pull request #241 from php-flasher/themes
add sapphire theme
2025-03-08 11:49:15 +00:00
Younes ENNAJI 8d5cadcf66 add sapphire theme 2025-03-08 11:48:51 +00:00
Younes ENNAJI 3c2b4c5546 Merge pull request #240 from php-flasher/themes
add ruby theme
2025-03-08 11:48:34 +00:00
Younes ENNAJI 12c1ca36c7 add ruby theme 2025-03-08 11:48:08 +00:00
Younes ENNAJI 9355c6a590 Merge pull request #239 from php-flasher/themes
add onyx theme
2025-03-08 11:47:56 +00:00
Younes ENNAJI 88e0de8417 add onyx theme 2025-03-08 11:47:26 +00:00
Younes ENNAJI 8aa67d017c Merge pull request #238 from php-flasher/themes
add neon theme
2025-03-08 11:47:05 +00:00
Younes ENNAJI 6b6204d264 add neon theme 2025-03-08 11:46:44 +00:00
Younes ENNAJI 50142d062e Merge pull request #237 from php-flasher/themes
add minimal theme
2025-03-08 11:46:21 +00:00
Younes ENNAJI b18069893b add minimal theme 2025-03-08 11:45:22 +00:00
Younes ENNAJI fa414e7ae5 Merge pull request #236 from php-flasher/themes
add material theme
2025-03-08 11:45:07 +00:00
Younes ENNAJI 1d48abf3b7 add material theme 2025-03-08 11:44:39 +00:00
Younes ENNAJI 43626a656b Merge pull request #235 from php-flasher/themes
add jade theme
2025-03-08 11:44:22 +00:00
Younes ENNAJI c5a6e20552 add jade theme 2025-03-08 11:44:00 +00:00
Younes ENNAJI b02a55e6a6 Merge pull request #234 from php-flasher/themes
add ios theme
2025-03-08 11:43:44 +00:00
Younes ENNAJI 176b616773 add ios theme 2025-03-08 11:43:03 +00:00
Younes ENNAJI 783822826c Merge pull request #233 from php-flasher/themes
add google theme
2025-03-08 11:42:40 +00:00
Younes ENNAJI 25ce040d00 add google theme 2025-03-08 11:42:14 +00:00
Younes ENNAJI 6ae8779f8f Merge pull request #232 from php-flasher/themes
refactor flasher theme
2025-03-08 11:42:00 +00:00
Younes ENNAJI 7fafa513a2 refactor flasher theme 2025-03-08 11:41:35 +00:00
Younes ENNAJI d20a7de308 Merge pull request #231 from php-flasher/themes
add facebook theme
2025-03-08 11:41:16 +00:00
Younes ENNAJI e1a6a85c76 add facebook theme 2025-03-08 11:40:49 +00:00
Younes ENNAJI 565438eb9f Merge pull request #230 from php-flasher/themes
add emerald theme
2025-03-08 11:40:37 +00:00
Younes ENNAJI efea45f892 add emerald theme 2025-03-08 11:40:12 +00:00
Younes ENNAJI f0bf6c61ab Merge pull request #229 from php-flasher/themes
add crystal theme
2025-03-08 11:39:55 +00:00
Younes ENNAJI f3b6183449 Merge pull request #228 from php-flasher/themes
add aurora theme
2025-03-08 11:39:20 +00:00
Younes ENNAJI d10e93b56f add crystal theme 2025-03-08 11:39:11 +00:00
Younes ENNAJI b88afe29b9 Merge pull request #227 from php-flasher/themes
add amber theme
2025-03-08 11:38:35 +00:00
Younes ENNAJI 13c72935ba add aurora theme 2025-03-08 11:38:29 +00:00
Younes ENNAJI 7fee53a92a Merge pull request #226 from php-flasher/themes
add amazon theme
2025-03-08 11:37:50 +00:00
Younes ENNAJI 8ee2442b9c add amber theme 2025-03-08 11:37:24 +00:00
Younes ENNAJI 99484054f9 Merge pull request #225 from php-flasher/themes
chore: prepare flasher to add themes + improve code documentation
2025-03-08 11:36:28 +00:00
Younes ENNAJI 3be978fc53 add amazon theme 2025-03-08 11:36:10 +00:00
Younes ENNAJI fe773941e4 chore: prepare flasher to add themes + improve code documentation 2025-03-08 11:34:23 +00:00
Younes ENNAJI 63fc0d9640 Merge pull request #224 from php-flasher/themes
chore: improve build scripts
2025-03-08 11:31:06 +00:00
Younes ENNAJI 4a83adb4f3 upgrade dependencies 2025-03-08 11:30:53 +00:00
Younes ENNAJI 3d66271ac8 update build scripts 2025-03-08 11:29:23 +00:00
Younes ENNAJI 29cea6f9d3 Merge pull request #223 from php-flasher/laravel-12
add tests for laravel 12
2025-02-26 09:14:46 +00:00
Younes ENNAJI 47ad265fb4 test laravel v12 with phpunit v11.5 2025-02-26 09:12:41 +00:00
Younes ENNAJI 99371ede9e add tests for laravel 12 2025-02-26 09:10:27 +00:00
Younes ENNAJI 6e8884d1d1 Merge pull request #222 from php-flasher/docs
Update github action file
2025-02-23 14:08:18 +00:00
Younes ENNAJI 2c95b4e6ba Wip 2025-02-23 14:05:54 +00:00
Younes ENNAJI 4b3fb8f584 Wip 2025-02-23 14:04:49 +00:00
Younes ENNAJI 40e9e83e3a Wip 2025-02-23 14:03:53 +00:00
Younes ENNAJI 59ead448e9 Wip 2025-02-23 14:02:59 +00:00
Younes ENNAJI 1397e0bb59 Merge pull request #221 from php-flasher/docs
test laravel 11 on php v8.4
2025-02-23 13:54:51 +00:00
Younes ENNAJI 56e610d6b0 test laravel 11 on php v8.4 2025-02-23 13:53:44 +00:00
Younes ENNAJI ba3dd5fe7f Merge pull request #220 from php-flasher/docs
docs
2025-02-23 13:51:02 +00:00
Younes ENNAJI d9699b7fe2 Wip 2025-02-23 13:49:16 +00:00
Younes ENNAJI ed742de9db update documentation head.html 2025-02-23 12:09:13 +00:00
Younes ENNAJI 8fdc809118 remove progress bar 2025-02-21 22:10:00 +01:00
Younes ENNAJI dfdd28b869 Wip 2025-02-21 22:01:54 +01:00
Younes ENNAJI a539235d1a update bin/release file 2025-02-21 21:58:05 +01:00
Younes ENNAJI df08f255d3 Merge pull request #219 from php-flasher/split-script
split script
2025-02-21 21:49:50 +01:00
Younes ENNAJI 31d5cb6e8e Wip 2025-02-21 21:47:42 +01:00
Younes ENNAJI d2750dee8a Wip 2025-02-21 21:46:14 +01:00
Younes ENNAJI 43553ad8ad Wip 2025-02-21 21:43:50 +01:00
Younes ENNAJI 48b2c0fae0 Wip 2025-02-21 21:27:56 +01:00
Younes ENNAJI 0988fdca9d improve the bin/split script 2025-02-21 21:20:40 +01:00
Younes ENNAJI a24159c3f0 Merge pull request #218 from php-flasher/scripts
bump flasher to v2.1.6
2025-02-21 21:07:26 +01:00
Younes ENNAJI f9c9ecf18e bump flasher to v2.1.6 2025-02-21 21:05:00 +01:00
Younes ENNAJI f93a908d25 update task file and bump script 2025-02-21 21:02:15 +01:00
Younes ENNAJI 1237b5f552 Wip 2025-02-21 20:44:12 +01:00
Younes ENNAJI bce970de5f Merge pull request #217 from php-flasher/scripts
update bin scripts
2025-02-21 20:30:33 +01:00
Younes ENNAJI 8809cd9ddf update taskfile 2025-02-21 20:28:11 +01:00
Younes ENNAJI fdbc5fd270 Wip 2025-02-21 20:12:25 +01:00
Younes ENNAJI 3d5d8d3c9a Wip 2025-02-21 19:43:37 +01:00
Younes ENNAJI 9d1bbc5d9a Wip 2025-02-21 19:35:48 +01:00
Younes ENNAJI aee6d2764a Merge pull request #216 from php-flasher/v2.1.5
prepare for v2.1.5
2025-02-21 18:55:10 +01:00
Younes ENNAJI a26cac3a07 prepare for v2.1.5 2025-02-21 18:52:39 +01:00
Younes ENNAJI 811fc1a5eb Merge pull request #215 from php-flasher/v2.1.4
chore: bump flasher dependency to v2.1.4
2025-02-18 14:02:26 +01:00
Younes ENNAJI 1b3b0bd08f add support for laravel v12 2025-02-18 14:01:24 +01:00
Younes ENNAJI 7972fd2d46 chore: bump flasher dependency to v2.1.4 2025-02-18 13:58:18 +01:00
Younes ENNAJI 31e2725566 Merge pull request #214 from php-flasher/issues/213
Fix PHPStan issue by removing includes section from composer.json
2025-02-18 13:54:49 +01:00
Younes ENNAJI b31695ff58 Remove phpstan includes section from composer.json 2025-02-18 13:51:41 +01:00
Younes ENNAJI a314692534 update assets version in package.json to v2.1.3 2025-01-25 14:59:20 +01:00
Younes ENNAJI 9de126bb55 update CHANGELOG 2025-01-25 14:38:48 +01:00
Younes ENNAJI f66382e324 Merge pull request #211 from ToshY/feature/208
Add GitHub workflow for automatic publishing of assets to NPM
2025-01-25 14:31:49 +01:00
ToshY e2ef4f08a4 add workflow for automatic publishing of assets to NPM 2025-01-23 00:24:45 +01:00
Younes ENNAJI 1e1b70e59b docs: upgrade dependencies and build assets 2025-01-19 18:50:40 +01:00
Younes ENNAJI 0ca4b5c197 Merge pull request #210 from php-flasher/upgrade-dependencies
upgrade dependencies
2025-01-18 11:34:10 +01:00
Younes ENNAJI df8eb83abe chore: update CHANGELOG 2025-01-18 11:30:44 +01:00
Younes ENNAJI 3f1b22a126 chore: bump flasher dependency to v2.1.2 2025-01-18 11:26:31 +01:00
Younes ENNAJI b11524c2f9 update demo files 2025-01-18 11:23:18 +01:00
Younes ENNAJI a2333762ea build documentation 2025-01-18 11:23:18 +01:00
Younes ENNAJI 3e2e853022 upgrade dependencies 2025-01-18 11:23:17 +01:00
Younes ENNAJI 27904be912 Merge pull request #209 from php-flasher/issues/208
feat: make mainScript nullable
2025-01-18 11:22:59 +01:00
Younes ENNAJI c9d3b56346 feat: make mainScript nullable 2025-01-17 10:28:13 +01:00
Younes ENNAJI db485d1ff2 Merge pull request #207 from BrookeDot/patch-2
Update Flasher Class Parameter Order
2024-11-09 00:38:24 +01:00
Brooke. 707c7a42e1 Update Flasher Class Parameter Order
The order of `$title` and `$options` has changed, if one tries to pass a string to parameter three ($options) an error is thrown. This updates the docs accordingly.

Looks like the order was changed here:
https://github.com/php-flasher/php-flasher/blob/2.x/src/Prime/helpers.php#L21-L36
2024-11-08 13:33:52 -08:00
Younes ENNAJI 456016a585 docs: update contributors list 2024-11-06 22:52:07 +01:00
Younes ENNAJI a38ddbb53a Merge pull request #206 from BrookeDot/patch-1
Fix 404s and add links to new Guides to Getting Started
2024-11-06 22:43:03 +01:00
Brooke. 5a73173dcf Fix 404s and add links to new Guides to Getting Started
Fixes the 404s for Laravel and Symfony links (due to case sensitivity) and adds the Livewire and Inertia guides to the Getting Started section
2024-11-06 13:23:50 -08:00
Younes ENNAJI 7abdccf284 Add PR template and auto-close PR on subtree split repositories 2024-10-27 16:04:49 +01:00
Younes ENNAJI a34a943397 docs: update laravel README.md add preset example 2024-10-27 15:31:54 +01:00
Younes ENNAJI fe4601bb8b docs: update symfony README.md file 2024-10-27 15:29:49 +01:00
Younes ENNAJI 86a56f4cff docs: update laravel markdown file 2024-10-27 15:02:54 +01:00
Younes ENNAJI c3493a7335 docs: update header links inside of README.md file 2024-10-27 14:16:24 +01:00
Younes ENNAJI b2a102023b docs: update README.md file 2024-10-27 14:12:39 +01:00
Younes ENNAJI 2a85dc37c3 chore: upgrade dependencies 2024-10-27 12:16:39 +01:00
770 changed files with 59196 additions and 13226 deletions
+9
View File
@@ -95,6 +95,15 @@
"code",
"doc"
]
},
{
"login": "BrookeDot",
"name": "Brooke.",
"avatar_url": "https://avatars.githubusercontent.com/u/150348?v=4",
"profile": "https://github.com/BrookeDot",
"contributions": [
"doc"
]
}
]
}
+1
View File
@@ -1,3 +1,4 @@
> 1%
last 2 versions
not dead
not IE 11
-1
View File
@@ -1,2 +1 @@
github: yoeunes
custom: https://www.paypal.com/paypalme/yoeunes
+61
View File
@@ -0,0 +1,61 @@
name: 🚀 Publish assets to NPM
on:
release:
types: [ published ]
jobs:
publish-prime:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./src/Prime/Resources
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20.x'
registry-url: 'https://registry.npmjs.org'
- name: Install dependencies
run: npm install
- name: Publish to NPM
run: npm publish --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
publish-plugin:
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
strategy:
fail-fast: false
matrix:
path:
- ./src/Noty/Prime/Resources
- ./src/Notyf/Prime/Resources
- ./src/SweetAlert/Prime/Resources
- ./src/Toastr/Prime/Resources
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20.x'
registry-url: 'https://registry.npmjs.org'
- name: Install dependencies
run: npm install
working-directory: ${{ matrix.path }}
- name: Publish to NPM
run: npm publish --access public
working-directory: ${{ matrix.path }}
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
+15 -12
View File
@@ -1,4 +1,4 @@
name: 🧪 Run Tests & 🛠️ Static Analysis
name: qa
on:
push:
@@ -17,7 +17,7 @@ jobs:
matrix:
php: [ 8.2 ]
name: 🐘 PHP ${{ matrix.php }} Static Analysis
name: php v${{ matrix.php }}
steps:
- name: 📥 Checkout Code
@@ -39,18 +39,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 +61,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 +85,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
@@ -101,7 +102,7 @@ jobs:
- { 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
@@ -126,7 +127,7 @@ jobs:
composer config --global allow-plugins true
composer config extra.symfony.require "${{ matrix.symfony }}"
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
composer update --prefer-lowest -W --no-interaction --prefer-dist --optimize-autoloader
- name: ✅ Execute tests
run: vendor/bin/phpunit --testsuite symfony
@@ -137,10 +138,12 @@ jobs:
fail-fast: false
matrix:
include:
- { laravel: 11.*, testbench: 9.*, php: 8.3, phpunit: 10.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
@@ -165,7 +168,7 @@ jobs:
sed -i '/\"require\": {/,/},/d; /\"require-dev\": {/,/},/d' composer.json
composer config --global allow-plugins true
composer require "laravel/framework:${{ matrix.laravel }}" "phpunit/phpunit:${{ matrix.phpunit }}" "orchestra/testbench:${{ matrix.testbench }}" --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 laravel
+5 -2
View File
@@ -1,4 +1,7 @@
{
"upgrade": true,
"target": "semver"
"upgrade": true,
"target": "semver",
"format": "group",
"color": true,
"root": true
}
-2
View File
@@ -1,2 +0,0 @@
ignore-workspace-root-check=true
shell-emulator=true
-1
View File
@@ -1,2 +1 @@
github: yoeunes
custom: https://www.paypal.com/paypalme/yoeunes
+8
View File
@@ -0,0 +1,8 @@
Please do not submit any Pull Requests here. They will be closed.
---
Please submit your PR here instead:
https://github.com/php-flasher/php-flasher
This repository is what we call a "subtree split": a read-only subset of that main repository.
We're looking forward to your PR there!
+20
View File
@@ -0,0 +1,20 @@
name: Close Pull Request
on:
pull_request_target:
types: [opened]
jobs:
run:
runs-on: ubuntu-latest
steps:
- uses: superbrothers/close-pull-request@v3
with:
comment: |
Thanks for your Pull Request! We love contributions.
However, you should instead open your PR on the main repository:
https://github.com/php-flasher/php-flasher
This repository is what we call a "subtree split": a read-only subset of that main repository.
We're looking forward to your PR there!
+9 -1
View File
@@ -1,6 +1,14 @@
# CHANGELOG for 2.x
## [Unreleased](https://github.com/php-flasher/php-flasher/compare/v2.1.1...2.x)
## [Unreleased](https://github.com/php-flasher/php-flasher/compare/v2.1.4...2.x)
## [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)
## [v2.1.2](https://github.com/php-flasher/php-flasher/compare/v2.1.1...v2.1.2) - 2025-01-18
* bug [#208](https://github.com/php-flasher/php-flasher/issues/208) [Flasher] Allow `main_script` to be nullable. See [PR #209](https://github.com/php-flasher/php-flasher/pull/209) by [yoeunes](https://github.com/yoeunes)
## [v2.1.1](https://github.com/php-flasher/php-flasher/compare/v2.1.0...v2.1.1) - 2024-10-20
+519 -14
View File
@@ -6,28 +6,526 @@
<p align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/php-flasher/art/main/php-flasher-github-dark.png">
<img src="https://raw.githubusercontent.com/php-flasher/art/main/php-flasher-github.png" alt="PHPFlasher Logo">
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/php-flasher/art/main/php-flasher-logo-dark.png">
<img src="https://raw.githubusercontent.com/php-flasher/art/main/php-flasher-logo.png" alt="PHPFlasher Logo">
</picture>
</p>
## About PHPFlasher
<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>
</p>
PHPFlasher is a powerful and easy-to-use package that allows you to quickly and easily add flash messages to your Laravel or Symfony projects.
Whether you need to alert users of a successful form submission, an error, or any other important information, flash messages are a simple and effective solution for providing feedback to your users.
# PHPFlasher: Beautiful Notifications Made Simple
With PHPFlasher, you can easily record and store messages within the session, making it simple to retrieve and display them on the current or next page.
This improves user engagement and enhances the overall user experience on your website or application.
## 🚀 See It In Action
Whether you're a beginner or an experienced developer, PHPFlasher's intuitive and straightforward design makes it easy to integrate into your projects.
So, if you're looking for a reliable, flexible and easy to use flash messages solution, PHPFlasher is the perfect choice.
```php
// In your controller
public function updateProfile(Request $request)
{
// Process form submission
$user = Auth::user();
$user->update($request->validated());
// Show a beautiful notification to the user
flash()->success('Your profile has been updated successfully!');
return redirect()->back();
}
```
That's it! PHPFlasher will display an elegant success notification to your user. No JavaScript to write, no frontend setup needed.
## Official Documentation
## 🔄 Compatibility
Documentation for PHPFlasher can be found on the [https://php-flasher.io](https://php-flasher.io).
| Requirements | Version |
|--------------|---------|
| PHP | ≥ 8.2 |
| Laravel | ≥ 11.0 |
| Symfony | ≥ 7.0 |
## Contributors and sponsors
## 📑 Table of Contents
- [Introduction](#-introduction)
- [Features](#-key-features)
- [Installation](#-installation)
- [Usage Examples](#-usage-examples)
- [Themes](#-themes)
- [Adapters](#-adapters)
- [Advanced Configuration](#-advanced-configuration)
- [Adapter Documentation Example](#-adapter-documentation-example)
- [Community & Support](#-community--support)
- [Contributors](#-contributors-and-sponsors)
- [License](#-license)
## 🌟 Introduction
PHPFlasher is a powerful, framework-agnostic library that makes it simple to add beautiful flash messages to your web applications. It provides a consistent API for displaying notifications across your PHP applications, whether you're using Laravel, Symfony, or any other PHP framework.
Flash messages are short-lived notifications that appear after a user performs an action, such as submitting a form. PHPFlasher helps you create these notifications with minimal effort while ensuring they look great and behave consistently.
## ✨ Key Features
- **Zero JavaScript Required**: Write only PHP code - frontend functionality is handled automatically
- **Framework Support**: First-class Laravel and Symfony integration
- **Beautiful Themes**: Multiple built-in themes ready to use out of the box
- **Multiple Notification Types**: Success, error, warning, and info notifications
- **Highly Customizable**: Positions, timeouts, animations, and more
- **Third-Party Adapters**: Integration with popular libraries like Toastr, SweetAlert, and more
- **API Response Support**: Works with AJAX and API responses
- **TypeScript Support**: Full TypeScript definitions for frontend customization
- **Lightweight**: Minimal performance impact
## 📦 Installation
### For Laravel Projects
```bash
# Install the Laravel adapter
composer require php-flasher/flasher-laravel
# Set up assets automatically
php artisan flasher:install
```
PHPFlasher automatically injects the necessary JavaScript and CSS assets into your Blade templates. No additional setup required!
### For Symfony Projects
```bash
# Install the Symfony adapter
composer require php-flasher/flasher-symfony
# Set up assets automatically
php bin/console flasher:install
```
PHPFlasher automatically injects the necessary JavaScript and CSS assets into your Twig templates.
## 📚 Usage Examples
### Basic Notifications
```php
// Success notification
flash()->success('Operation completed successfully!');
// Error notification
flash()->error('An error occurred. Please try again.');
// Info notification
flash()->info('Your account will expire in 10 days.');
// Warning notification
flash()->warning('Please backup your data before continuing.');
```
### With Custom Titles
```php
flash()->success('Your changes have been saved!', 'Update Successful');
flash()->error('Unable to connect to the server.', 'Connection Error');
```
### With Custom Options
```php
flash()->success('Profile updated successfully!', [
'timeout' => 10000, // Display for 10 seconds
'position' => 'bottom-right',
'closeButton' => true,
]);
flash()->error('Failed to submit form.', 'Error', [
'timeout' => 0, // No timeout (stay until dismissed)
'position' => 'center',
]);
```
### In Controllers
```php
// Laravel
public function store(Request $request)
{
// Process form...
flash()->success('Product created successfully!');
return redirect()->route('products.index');
}
// Symfony
public function store(Request $request, FlasherInterface $flasher)
{
// Process form...
$flasher->success('Product created successfully!');
return $this->redirectToRoute('products.index');
}
```
### Specific Use Cases
```php
// Form validation errors
if ($validator->fails()) {
flash()->error('Please fix the errors in your form.');
return redirect()->back()->withErrors($validator);
}
// Multi-step process
flash()->success('Step 1 completed!');
flash()->info('Please complete step 2.');
// With HTML content (must enable HTML option)
flash()->success('Your <strong>account</strong> is ready!', [
'escapeHtml' => false
]);
```
## 🎨 Themes
PHPFlasher comes with beautiful built-in themes ready to use immediately:
### Default Theme (Flasher)
The default theme provides clean, elegant notifications that work well in any application:
```php
flash()->success('Operation completed!');
```
### Other Built-In Themes
PHPFlasher includes multiple themes to match your application's design:
```php
// Set the theme in your configuration or per notification
flash()->success('Operation completed!', [
'theme' => 'amazon' // Amazon-inspired theme
]);
// Other available themes:
// - amber: Warm amber styling
// - aurora: Subtle gradient effects
// - crystal: Clean, transparent design
// - emerald: Green-focused modern look
// - facebook: Facebook notification style
// - google: Google Material Design inspired
// - ios: iOS notification style
// - jade: Soft jade color palette
// - material: Material Design implementation
// - minimal: Extremely clean and simple
// - neon: Bright, attention-grabbing
// - onyx: Dark mode sleek design
// - ruby: Bold ruby red accents
// - sapphire: Blue-focused elegant style
// - slack: Slack-inspired notifications
```
### Theme Configuration
You can configure theme defaults in your configuration file:
```php
// Laravel: config/flasher.php
return [
'themes' => [
'flasher' => [
'options' => [
'timeout' => 5000,
'position' => 'top-right',
],
],
'amazon' => [
'options' => [
'timeout' => 3000,
'position' => 'bottom-right',
],
],
],
];
```
## 🧩 Adapters
Beyond PHPFlasher's built-in themes, you can use third-party notification libraries:
### Available Adapters
#### Toastr
```bash
composer require php-flasher/flasher-toastr-laravel # For Laravel
composer require php-flasher/flasher-toastr-symfony # For Symfony
```
```php
flash('toastr')->success('Message with Toastr!');
```
#### SweetAlert
```bash
composer require php-flasher/flasher-sweetalert-laravel # For Laravel
composer require php-flasher/flasher-sweetalert-symfony # For Symfony
```
```php
flash('sweetalert')->success('Message with SweetAlert!');
```
#### Noty
```bash
composer require php-flasher/flasher-noty-laravel # For Laravel
composer require php-flasher/flasher-noty-symfony # For Symfony
```
```php
flash('noty')->success('Message with Noty!');
```
#### Notyf
```bash
composer require php-flasher/flasher-notyf-laravel # For Laravel
composer require php-flasher/flasher-notyf-symfony # For Symfony
```
```php
flash('notyf')->success('Message with Notyf!');
```
## ⚙️ Advanced Configuration
### Laravel Configuration
Publish and customize the configuration:
```bash
php artisan vendor:publish --tag=flasher-config
```
This creates `config/flasher.php` where you can configure:
```php
return [
// Default adapter to use
'default' => 'flasher',
// Theme configuration
'themes' => [
'flasher' => [
'options' => [
'timeout' => 5000,
'position' => 'top-right',
],
],
],
// Auto-convert Laravel session flash messages
'auto_create_from_session' => true,
// Automatically render notifications
'auto_render' => true,
// Type mappings for Laravel notifications
'types_mapping' => [
'success' => 'success',
'error' => 'error',
'warning' => 'warning',
'info' => 'info',
],
];
```
### Symfony Configuration
Create or edit `config/packages/flasher.yaml`:
```yaml
flasher:
default: flasher
themes:
flasher:
options:
timeout: 5000
position: top-right
auto_create_from_session: true
auto_render: true
types_mapping:
success: success
error: error
warning: warning
info: info
```
### Notification Options
Common options you can customize:
```php
flash()->success('Message', [
// Display duration in milliseconds (0 = until dismissed)
'timeout' => 5000,
// Notification position
'position' => 'top-right', // top-right, top-left, bottom-right, bottom-left, top-center, bottom-center
// Display a close button
'closeButton' => true,
// Show progress bar during timeout
'progressBar' => true,
// Right-to-left text direction
'rtl' => false,
// Allow HTML content in notifications
'escapeHtml' => false,
// Custom CSS class
'class' => 'my-custom-notification',
]);
```
## 📘 Adapter Documentation Example
Here's a detailed example of using the Toastr adapter with PHPFlasher:
### Installation
```bash
composer require php-flasher/flasher-toastr
```
For Laravel:
```bash
composer require php-flasher/flasher-toastr-laravel
```
For Symfony:
```bash
composer require php-flasher/flasher-toastr-symfony
```
### Usage
#### Basic Usage
```php
use Flasher\Toastr\Prime\ToastrFactory;
// Inject the factory
public function __construct(private ToastrFactory $toastr)
{
}
public function index()
{
$this->toastr->success('Toastr is working!');
// Or using the global helper with the specified adapter
flash('toastr')->success('Toastr is awesome!');
}
```
#### With Options
```php
flash('toastr')->success('Success message', 'Success Title', [
'timeOut' => 5000,
'closeButton' => true,
'newestOnTop' => true,
'progressBar' => true,
'positionClass' => 'toast-top-right',
]);
```
#### Available Methods
```php
// Standard notification types
flash('toastr')->success('Success message');
flash('toastr')->info('Information message');
flash('toastr')->warning('Warning message');
flash('toastr')->error('Error message');
// Custom notification
flash('toastr')->flash('custom-type', 'Custom message');
```
#### Toastr Specific Options
| Option | Type | Default | Description |
|------------------|---------|----------------|--------------------------------------------|
| closeButton | Boolean | false | Display a close button |
| closeClass | String | 'toast-close-button' | CSS class for close button |
| newestOnTop | Boolean | true | Add notifications to the top of the stack |
| progressBar | Boolean | true | Display progress bar |
| positionClass | String | 'toast-top-right' | Position of the notification |
| preventDuplicates | Boolean | false | Prevent duplicates |
| showDuration | Number | 300 | Show animation duration in ms |
| hideDuration | Number | 1000 | Hide animation duration in ms |
| timeOut | Number | 5000 | Auto-close duration (0 = disable) |
| extendedTimeOut | Number | 1000 | Duration after hover |
| showEasing | String | 'swing' | Show animation easing |
| hideEasing | String | 'linear' | Hide animation easing |
| showMethod | String | 'fadeIn' | Show animation method |
| hideMethod | String | 'fadeOut' | Hide animation method |
### Advanced Configuration
#### Laravel Configuration
Publish the configuration file:
```bash
php artisan vendor:publish --tag=flasher-toastr-config
```
#### Symfony Configuration
Edit your `config/packages/flasher.yaml`:
```yaml
flasher:
toastr:
options:
timeOut: 5000
progressBar: true
```
## Learn More
For additional information, see the [PHPFlasher documentation](https://php-flasher.io).
## 👥 Community & Support
### Getting Help
- **Documentation**: Visit [https://php-flasher.io](https://php-flasher.io)
- **GitHub Issues**: [Report bugs or request features](https://github.com/php-flasher/php-flasher/issues)
- **Stack Overflow**: Ask questions with the `php-flasher` tag
### Common Use Cases
- Form submission feedback
- AJAX request notifications
- Authentication messages
- Error reporting
- Success confirmations
- System alerts
## 🌟 Contributors and Sponsors
Join our team of contributors and make a lasting impact on our project!
@@ -53,6 +551,7 @@ Shining stars of our community:
<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>
@@ -62,7 +561,7 @@ Shining stars of our community:
<!-- ALL-CONTRIBUTORS-LIST:END -->
## Contact
## 📬 Contact
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:
@@ -73,8 +572,14 @@ You can reach out with questions, bug reports, or feature requests on any of the
- [Linkedin](https://www.linkedin.com/in/younes--ennaji/)
- [Email me directly](mailto:younes.ennaji.pro@gmail.com)
## License
## 📝 License
PHPFlasher is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT).
<p align="center"> <b>Made with ❤️ by <a href="https://www.linkedin.com/in/younes--ennaji/">Younes ENNAJI</a> </b> </p>
<p align="center">
<a href="https://github.com/php-flasher/php-flasher/stargazers">
⭐ Star if you found this useful ⭐
</a>
</p>
Executable
+675
View File
@@ -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 "$@"
Executable
+189
View File
@@ -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"
+27 -62
View File
@@ -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."
-35
View File
@@ -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."
Executable
+101
View File
@@ -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 "$@"
Executable
+158
View File
@@ -0,0 +1,158 @@
#!/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 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 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 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 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 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 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
}
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
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
Executable
+225
View File
@@ -0,0 +1,225 @@
#!/usr/bin/env bash
# Set options
set -o pipefail
# 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"
)
# 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}"
}
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
View File
@@ -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 "$@"
+132 -86
View File
@@ -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
View File
@@ -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
View File
@@ -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
+3 -4
View File
@@ -22,9 +22,9 @@
"require": {
"php": ">=8.2",
"ext-intl": "*",
"illuminate/contracts": "^11.0",
"illuminate/routing": "^11.0",
"illuminate/support": "^11.0",
"illuminate/contracts": "^11.0|^12.0",
"illuminate/routing": "^11.0|^12.0",
"illuminate/support": "^11.0|^12.0",
"laravel/octane": "^2.3",
"livewire/livewire": "^3.0",
"paragonie/random_compat": "^2.0",
@@ -51,7 +51,6 @@
"phpunit/phpunit": "^10.5.26",
"rector/rector": "^1.2.8",
"rector/swiss-knife": "^1.0.0",
"spatie/ray": "^1.41.2",
"symplify/monorepo-builder": "^11.2.22"
},
"autoload": {
Generated
+149 -154
View File
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "ddb7aadf973fbf84a14d002bdfa9c226",
"content-hash": "d5de08e384654736feea63f1b01ffba1",
"packages": [
{
"name": "brick/math",
@@ -1057,8 +1057,8 @@
"type": "library",
"extra": {
"laminas": {
"config-provider": "Laminas\\Diactoros\\ConfigProvider",
"module": "Laminas\\Diactoros"
"module": "Laminas\\Diactoros",
"config-provider": "Laminas\\Diactoros\\ConfigProvider"
}
},
"autoload": {
@@ -1357,16 +1357,16 @@
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.x-dev"
},
"laravel": {
"providers": [
"Laravel\\Octane\\OctaneServiceProvider"
],
"aliases": {
"Octane": "Laravel\\Octane\\Facades\\Octane"
}
},
"providers": [
"Laravel\\Octane\\OctaneServiceProvider"
]
},
"branch-alias": {
"dev-master": "2.x-dev"
}
},
"autoload": {
@@ -1883,12 +1883,12 @@
"type": "library",
"extra": {
"laravel": {
"providers": [
"Livewire\\LivewireServiceProvider"
],
"aliases": {
"Livewire": "Livewire\\Livewire"
}
},
"providers": [
"Livewire\\LivewireServiceProvider"
]
}
},
"autoload": {
@@ -2030,12 +2030,12 @@
"version": "3.0.0",
"source": {
"type": "git",
"url": "https://github.com/briannesbitt/Carbon.git",
"url": "https://github.com/CarbonPHP/carbon.git",
"reference": "7ae1c6fd10d2a93a0a0f5ab8fc8be37cb0830dec"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/7ae1c6fd10d2a93a0a0f5ab8fc8be37cb0830dec",
"url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/7ae1c6fd10d2a93a0a0f5ab8fc8be37cb0830dec",
"reference": "7ae1c6fd10d2a93a0a0f5ab8fc8be37cb0830dec",
"shasum": ""
},
@@ -2068,10 +2068,6 @@
],
"type": "library",
"extra": {
"branch-alias": {
"dev-3.x": "3.x-dev",
"dev-master": "2.x-dev"
},
"laravel": {
"providers": [
"Carbon\\Laravel\\ServiceProvider"
@@ -2081,6 +2077,10 @@
"includes": [
"extension.neon"
]
},
"branch-alias": {
"dev-3.x": "3.x-dev",
"dev-master": "2.x-dev"
}
},
"autoload": {
@@ -3162,31 +3162,31 @@
},
{
"name": "symfony/cache",
"version": "v7.0.0",
"version": "v6.4.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/cache.git",
"reference": "5e2376f726d61541b9617512e374808d12c1dc22"
"reference": "ac2d25f97b17eec6e19760b6b9962a4f7c44356a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/cache/zipball/5e2376f726d61541b9617512e374808d12c1dc22",
"reference": "5e2376f726d61541b9617512e374808d12c1dc22",
"url": "https://api.github.com/repos/symfony/cache/zipball/ac2d25f97b17eec6e19760b6b9962a4f7c44356a",
"reference": "ac2d25f97b17eec6e19760b6b9962a4f7c44356a",
"shasum": ""
},
"require": {
"php": ">=8.2",
"php": ">=8.1",
"psr/cache": "^2.0|^3.0",
"psr/log": "^1.1|^2|^3",
"symfony/cache-contracts": "^2.5|^3",
"symfony/service-contracts": "^2.5|^3",
"symfony/var-exporter": "^6.4|^7.0"
"symfony/var-exporter": "^6.3.6|^7.0"
},
"conflict": {
"doctrine/dbal": "<3.6",
"symfony/dependency-injection": "<6.4",
"symfony/http-kernel": "<6.4",
"symfony/var-dumper": "<6.4"
"doctrine/dbal": "<2.13.1",
"symfony/dependency-injection": "<5.4",
"symfony/http-kernel": "<5.4",
"symfony/var-dumper": "<5.4"
},
"provide": {
"psr/cache-implementation": "2.0|3.0",
@@ -3195,15 +3195,15 @@
},
"require-dev": {
"cache/integration-tests": "dev-master",
"doctrine/dbal": "^3.6|^4",
"doctrine/dbal": "^2.13.1|^3|^4",
"predis/predis": "^1.1|^2.0",
"psr/simple-cache": "^1.0|^2.0|^3.0",
"symfony/config": "^6.4|^7.0",
"symfony/dependency-injection": "^6.4|^7.0",
"symfony/filesystem": "^6.4|^7.0",
"symfony/http-kernel": "^6.4|^7.0",
"symfony/messenger": "^6.4|^7.0",
"symfony/var-dumper": "^6.4|^7.0"
"symfony/config": "^5.4|^6.0|^7.0",
"symfony/dependency-injection": "^5.4|^6.0|^7.0",
"symfony/filesystem": "^5.4|^6.0|^7.0",
"symfony/http-kernel": "^5.4|^6.0|^7.0",
"symfony/messenger": "^5.4|^6.0|^7.0",
"symfony/var-dumper": "^5.4|^6.0|^7.0"
},
"type": "library",
"autoload": {
@@ -3238,7 +3238,7 @@
"psr6"
],
"support": {
"source": "https://github.com/symfony/cache/tree/v7.0.0"
"source": "https://github.com/symfony/cache/tree/v6.4.0"
},
"funding": [
{
@@ -3254,7 +3254,7 @@
"type": "tidelift"
}
],
"time": "2023-11-25T15:40:35+00:00"
"time": "2023-11-24T19:28:07+00:00"
},
{
"name": "symfony/cache-contracts",
@@ -3279,12 +3279,12 @@
},
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/contracts",
"name": "symfony/contracts"
},
"branch-alias": {
"dev-main": "2.5-dev"
},
"thanks": {
"name": "symfony/contracts",
"url": "https://github.com/symfony/contracts"
}
},
"autoload": {
@@ -3732,12 +3732,12 @@
},
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/contracts",
"name": "symfony/contracts"
},
"branch-alias": {
"dev-main": "2.5-dev"
},
"thanks": {
"name": "symfony/contracts",
"url": "https://github.com/symfony/contracts"
}
},
"autoload": {
@@ -3857,24 +3857,24 @@
},
{
"name": "symfony/event-dispatcher",
"version": "v7.0.0",
"version": "v6.4.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/event-dispatcher.git",
"reference": "c459b40ffe67c49af6fd392aac374c9edf8a027e"
"reference": "d76d2632cfc2206eecb5ad2b26cd5934082941b6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/c459b40ffe67c49af6fd392aac374c9edf8a027e",
"reference": "c459b40ffe67c49af6fd392aac374c9edf8a027e",
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/d76d2632cfc2206eecb5ad2b26cd5934082941b6",
"reference": "d76d2632cfc2206eecb5ad2b26cd5934082941b6",
"shasum": ""
},
"require": {
"php": ">=8.2",
"php": ">=8.1",
"symfony/event-dispatcher-contracts": "^2.5|^3"
},
"conflict": {
"symfony/dependency-injection": "<6.4",
"symfony/dependency-injection": "<5.4",
"symfony/service-contracts": "<2.5"
},
"provide": {
@@ -3883,13 +3883,13 @@
},
"require-dev": {
"psr/log": "^1|^2|^3",
"symfony/config": "^6.4|^7.0",
"symfony/dependency-injection": "^6.4|^7.0",
"symfony/error-handler": "^6.4|^7.0",
"symfony/expression-language": "^6.4|^7.0",
"symfony/http-foundation": "^6.4|^7.0",
"symfony/config": "^5.4|^6.0|^7.0",
"symfony/dependency-injection": "^5.4|^6.0|^7.0",
"symfony/error-handler": "^5.4|^6.0|^7.0",
"symfony/expression-language": "^5.4|^6.0|^7.0",
"symfony/http-foundation": "^5.4|^6.0|^7.0",
"symfony/service-contracts": "^2.5|^3",
"symfony/stopwatch": "^6.4|^7.0"
"symfony/stopwatch": "^5.4|^6.0|^7.0"
},
"type": "library",
"autoload": {
@@ -3917,7 +3917,7 @@
"description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/event-dispatcher/tree/v7.0.0"
"source": "https://github.com/symfony/event-dispatcher/tree/v6.4.0"
},
"funding": [
{
@@ -3933,7 +3933,7 @@
"type": "tidelift"
}
],
"time": "2023-07-27T16:29:09+00:00"
"time": "2023-07-27T06:52:43+00:00"
},
{
"name": "symfony/event-dispatcher-contracts",
@@ -3958,12 +3958,12 @@
},
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/contracts",
"name": "symfony/contracts"
},
"branch-alias": {
"dev-main": "2.5-dev"
},
"thanks": {
"name": "symfony/contracts",
"url": "https://github.com/symfony/contracts"
}
},
"autoload": {
@@ -4661,12 +4661,12 @@
},
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/polyfill",
"name": "symfony/polyfill"
},
"branch-alias": {
"dev-main": "1.23-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
},
"autoload": {
@@ -4942,12 +4942,12 @@
},
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/polyfill",
"name": "symfony/polyfill"
},
"branch-alias": {
"dev-main": "1.23-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
},
"autoload": {
@@ -5077,12 +5077,12 @@
},
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/polyfill",
"name": "symfony/polyfill"
},
"branch-alias": {
"dev-main": "1.23-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
},
"autoload": {
@@ -5160,12 +5160,12 @@
},
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/polyfill",
"name": "symfony/polyfill"
},
"branch-alias": {
"dev-main": "1.23-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
},
"autoload": {
@@ -5240,12 +5240,12 @@
},
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/polyfill",
"name": "symfony/polyfill"
},
"branch-alias": {
"dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
},
"autoload": {
@@ -5784,12 +5784,12 @@
},
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/contracts",
"name": "symfony/contracts"
},
"branch-alias": {
"dev-main": "3.4-dev"
},
"thanks": {
"name": "symfony/contracts",
"url": "https://github.com/symfony/contracts"
}
},
"autoload": {
@@ -6045,12 +6045,12 @@
},
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/contracts",
"name": "symfony/contracts"
},
"branch-alias": {
"dev-main": "2.5-dev"
},
"thanks": {
"name": "symfony/contracts",
"url": "https://github.com/symfony/contracts"
}
},
"autoload": {
@@ -6407,8 +6407,8 @@
"type": "symfony-bundle",
"extra": {
"thanks": {
"name": "symfony/ux",
"url": "https://github.com/symfony/ux"
"url": "https://github.com/symfony/ux",
"name": "symfony/ux"
}
},
"autoload": {
@@ -6454,16 +6454,16 @@
},
{
"name": "symfony/var-dumper",
"version": "v7.0.3",
"version": "v7.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/var-dumper.git",
"reference": "a7a061abbf6fe3d4a79032cbc5149a4d65a10234"
"reference": "cf0220fc7607476fd0d001ab3ed9e830d1fdda56"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/a7a061abbf6fe3d4a79032cbc5149a4d65a10234",
"reference": "a7a061abbf6fe3d4a79032cbc5149a4d65a10234",
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/cf0220fc7607476fd0d001ab3ed9e830d1fdda56",
"reference": "cf0220fc7607476fd0d001ab3ed9e830d1fdda56",
"shasum": ""
},
"require": {
@@ -6517,7 +6517,7 @@
"dump"
],
"support": {
"source": "https://github.com/symfony/var-dumper/tree/v7.0.3"
"source": "https://github.com/symfony/var-dumper/tree/v7.0.0"
},
"funding": [
{
@@ -6533,7 +6533,7 @@
"type": "tidelift"
}
],
"time": "2024-01-23T15:02:46+00:00"
"time": "2023-11-27T12:39:18+00:00"
},
{
"name": "symfony/var-exporter",
@@ -7252,13 +7252,13 @@
},
"type": "phpstan-extension",
"extra": {
"branch-alias": {
"dev-master": "2.0-dev"
},
"phpstan": {
"includes": [
"extension.neon"
]
},
"branch-alias": {
"dev-master": "2.0-dev"
}
},
"autoload": {
@@ -7712,13 +7712,13 @@
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "9.0-dev"
},
"laravel": {
"providers": [
"Orchestra\\Canvas\\LaravelServiceProvider"
]
},
"branch-alias": {
"dev-master": "9.0-dev"
}
},
"autoload": {
@@ -7780,13 +7780,13 @@
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "9.0-dev"
},
"laravel": {
"providers": [
"Orchestra\\Canvas\\Core\\LaravelServiceProvider"
]
},
"branch-alias": {
"dev-master": "9.0-dev"
}
},
"autoload": {
@@ -8028,16 +8028,16 @@
},
{
"name": "overtrue/phplint",
"version": "9.5.3",
"version": "9.5.6",
"source": {
"type": "git",
"url": "https://github.com/overtrue/phplint.git",
"reference": "584063a687abca041551e0b14c47fe9fc574b193"
"reference": "3fdc395a816d1401091062c7a3bfb31252aed6c5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/overtrue/phplint/zipball/584063a687abca041551e0b14c47fe9fc574b193",
"reference": "584063a687abca041551e0b14c47fe9fc574b193",
"url": "https://api.github.com/repos/overtrue/phplint/zipball/3fdc395a816d1401091062c7a3bfb31252aed6c5",
"reference": "3fdc395a816d1401091062c7a3bfb31252aed6c5",
"shasum": ""
},
"require": {
@@ -8045,14 +8045,14 @@
"ext-dom": "*",
"ext-json": "*",
"ext-mbstring": "*",
"php": "^8.2",
"symfony/cache": "^7.0",
"symfony/console": "^7.0",
"symfony/event-dispatcher": "^7.0",
"symfony/finder": "^7.0",
"symfony/options-resolver": "^7.0",
"symfony/process": "^7.0",
"symfony/yaml": "^7.0"
"php": "^8.1",
"symfony/cache": "^6.4 || ^7.0",
"symfony/console": "^6.4 || ^7.0",
"symfony/event-dispatcher": "^6.4 || ^7.0",
"symfony/finder": "^6.4 || ^7.0",
"symfony/options-resolver": "^6.4 || ^7.0",
"symfony/process": "^6.4 || ^7.0",
"symfony/yaml": "^6.4 || ^7.0"
},
"require-dev": {
"bamarni/composer-bin-plugin": "^1.4",
@@ -8065,17 +8065,17 @@
],
"type": "library",
"extra": {
"bamarni-bin": {
"bin-links": true,
"target-directory": "vendor-bin",
"forward-command": true
},
"hooks": {
"pre-commit": [
"composer style:fix",
"composer code:check"
]
},
"bamarni-bin": {
"bin-links": true,
"forward-command": true,
"target-directory": "vendor-bin"
},
"branch-alias": {
"dev-main": "9.5.x-dev"
}
@@ -8109,7 +8109,7 @@
],
"support": {
"issues": "https://github.com/overtrue/phplint/issues",
"source": "https://github.com/overtrue/phplint/tree/9.5.3"
"source": "https://github.com/overtrue/phplint/tree/9.5.6"
},
"funding": [
{
@@ -8117,7 +8117,7 @@
"type": "github"
}
],
"time": "2024-10-11T07:13:25+00:00"
"time": "2025-01-15T05:41:15+00:00"
},
{
"name": "phar-io/manifest",
@@ -9060,12 +9060,12 @@
],
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "0.12.x-dev"
},
"bamarni-bin": {
"bin-links": false,
"forward-command": false
},
"branch-alias": {
"dev-main": "0.12.x-dev"
}
},
"autoload": {
@@ -10213,13 +10213,13 @@
},
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.29.x-dev"
},
"laravel": {
"providers": [
"Spatie\\LaravelRay\\RayServiceProvider"
]
},
"branch-alias": {
"dev-main": "1.29.x-dev"
}
},
"autoload": {
@@ -10313,16 +10313,16 @@
},
{
"name": "spatie/ray",
"version": "1.41.2",
"version": "1.41.1",
"source": {
"type": "git",
"url": "https://github.com/spatie/ray.git",
"reference": "c44f8cfbf82c69909b505de61d8d3f2d324e93fc"
"reference": "051a0facb1d2462fafef87ff77eb74d6f2d12944"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/spatie/ray/zipball/c44f8cfbf82c69909b505de61d8d3f2d324e93fc",
"reference": "c44f8cfbf82c69909b505de61d8d3f2d324e93fc",
"url": "https://api.github.com/repos/spatie/ray/zipball/051a0facb1d2462fafef87ff77eb74d6f2d12944",
"reference": "051a0facb1d2462fafef87ff77eb74d6f2d12944",
"shasum": ""
},
"require": {
@@ -10333,7 +10333,7 @@
"spatie/backtrace": "^1.1",
"spatie/macroable": "^1.0|^2.0",
"symfony/stopwatch": "^4.0|^5.1|^6.0|^7.0",
"symfony/var-dumper": "^4.2|^5.1|^6.0|^7.0.3"
"symfony/var-dumper": "^4.2|^5.1|^6.0|^7.0"
},
"require-dev": {
"illuminate/support": "6.x|^8.18|^9.0",
@@ -10349,11 +10349,6 @@
"bin/remove-ray.sh"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.x-dev"
}
},
"autoload": {
"files": [
"src/helpers.php"
@@ -10382,7 +10377,7 @@
],
"support": {
"issues": "https://github.com/spatie/ray/issues",
"source": "https://github.com/spatie/ray/tree/1.41.2"
"source": "https://github.com/spatie/ray/tree/1.41.1"
},
"funding": [
{
@@ -10394,24 +10389,24 @@
"type": "other"
}
],
"time": "2024-04-24T14:21:46+00:00"
"time": "2024-01-25T10:15:50+00:00"
},
{
"name": "symfony/options-resolver",
"version": "v7.0.0",
"version": "v6.4.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/options-resolver.git",
"reference": "700ff4096e346f54cb628ea650767c8130f1001f"
"reference": "22301f0e7fdeaacc14318928612dee79be99860e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/options-resolver/zipball/700ff4096e346f54cb628ea650767c8130f1001f",
"reference": "700ff4096e346f54cb628ea650767c8130f1001f",
"url": "https://api.github.com/repos/symfony/options-resolver/zipball/22301f0e7fdeaacc14318928612dee79be99860e",
"reference": "22301f0e7fdeaacc14318928612dee79be99860e",
"shasum": ""
},
"require": {
"php": ">=8.2",
"php": ">=8.1",
"symfony/deprecation-contracts": "^2.5|^3"
},
"type": "library",
@@ -10445,7 +10440,7 @@
"options"
],
"support": {
"source": "https://github.com/symfony/options-resolver/tree/v7.0.0"
"source": "https://github.com/symfony/options-resolver/tree/v6.4.0"
},
"funding": [
{
@@ -10461,7 +10456,7 @@
"type": "tidelift"
}
],
"time": "2023-08-08T10:20:21+00:00"
"time": "2023-08-08T10:16:24+00:00"
},
{
"name": "symfony/polyfill-iconv",
+64
View File
@@ -0,0 +1,64 @@
APP_NAME=Laravel
APP_ENV=local
APP_KEY=base64:mNtM4UEOfGE4dx7IAH4+kx4iPYPdGeu+Gaw/PIcF4II=
APP_DEBUG=true
APP_TIMEZONE=UTC
APP_URL=http://localhost
APP_LOCALE=en
APP_FALLBACK_LOCALE=en
APP_FAKER_LOCALE=en_US
APP_MAINTENANCE_DRIVER=file
APP_MAINTENANCE_STORE=database
BCRYPT_ROUNDS=12
LOG_CHANNEL=stack
LOG_STACK=single
LOG_DEPRECATIONS_CHANNEL=null
LOG_LEVEL=debug
DB_CONNECTION=sqlite
# DB_HOST=127.0.0.1
# DB_PORT=3306
# DB_DATABASE=laravel
# DB_USERNAME=root
# DB_PASSWORD=
SESSION_DRIVER=database
SESSION_LIFETIME=120
SESSION_ENCRYPT=false
SESSION_PATH=/
SESSION_DOMAIN=null
BROADCAST_CONNECTION=log
FILESYSTEM_DISK=local
QUEUE_CONNECTION=database
CACHE_STORE=database
CACHE_PREFIX=
MEMCACHED_HOST=127.0.0.1
REDIS_CLIENT=phpredis
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
MAIL_MAILER=log
MAIL_HOST=127.0.0.1
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS="hello@example.com"
MAIL_FROM_NAME="${APP_NAME}"
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=
AWS_USE_PATH_STYLE_ENDPOINT=false
VITE_APP_NAME="${APP_NAME}"
-1
View File
@@ -6,7 +6,6 @@
/public/storage
/storage/*.key
/vendor
.env
.env.backup
.env.production
.phpunit.result.cache
@@ -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');
}
}
+20 -20
View File
@@ -15,26 +15,26 @@
],
"require": {
"php": "^8.2",
"inertiajs/inertia-laravel": "^1.0",
"laravel/framework": "^11.0",
"laravel/tinker": "^2.9",
"livewire/livewire": "^3.4",
"inertiajs/inertia-laravel": "^2.0.1",
"laravel/framework": "^12.3",
"laravel/tinker": "^2.10.1",
"livewire/livewire": "^3.6.2",
"php-flasher/php-flasher": "@dev",
"spatie/laravel-csp": "^2.9",
"spatie/laravel-ray": "^1.36"
"spatie/laravel-csp": "^2.10.3",
"spatie/laravel-ray": "^1.40.2"
},
"require-dev": {
"barryvdh/laravel-debugbar": "^3.14",
"fakerphp/faker": "^1.23",
"larastan/larastan": "^2.9",
"laravel/pint": "^1.13",
"laravel/sail": "^1.26",
"mockery/mockery": "^1.6",
"nunomaduro/collision": "^8.0",
"pestphp/pest": "^2.34",
"pestphp/pest-plugin-laravel": "^2.3",
"spatie/laravel-ignition": "^2.4",
"spatie/ray": "^1.41"
"barryvdh/laravel-debugbar": "^3.15.2",
"fakerphp/faker": "^1.24.1",
"larastan/larastan": "^3.2",
"laravel/pint": "^1.21.2",
"laravel/sail": "^1.41",
"mockery/mockery": "^1.6.12",
"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.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",
+1957 -1675
View File
File diff suppressed because it is too large Load Diff
+58 -8
View File
@@ -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
+4
View File
@@ -18,3 +18,7 @@
APP_ENV=dev
APP_SECRET=a2ee898b9e385a80ba8f7b11e97232b2
###< symfony/framework-bundle ###
###> symfony/mailer ###
MAILER_DSN=null://null
###< symfony/mailer ###
+1
View File
@@ -0,0 +1 @@
8.2
+1
View File
@@ -0,0 +1 @@
php=php@8.2
+21 -20
View File
@@ -16,21 +16,27 @@
"php": ">=8.2",
"ext-ctype": "*",
"ext-iconv": "*",
"nelmio/security-bundle": "^3.3",
"nelmio/security-bundle": "^3.4.2",
"php-flasher/php-flasher": "@dev",
"phpstan/phpstan-symfony": "^1.3",
"symfony/console": "7.0.*",
"symfony/dotenv": "7.0.*",
"symfony/flex": "^2",
"symfony/framework-bundle": "7.0.*",
"phpstan/phpstan-symfony": "^2.0.2",
"symfony/console": "7.2.*",
"symfony/dotenv": "7.2.*",
"symfony/flex": "^2.4.7",
"symfony/framework-bundle": "7.2.*",
"symfony/monolog-bundle": "^3.10",
"symfony/notifier": "7.0.*",
"symfony/runtime": "7.0.*",
"symfony/translation": "7.0.*",
"symfony/twig-bundle": "7.0.*",
"symfony/yaml": "7.0.*",
"twig/extra-bundle": "^2.12|^3.0",
"twig/twig": "^2.12|^3.0"
"symfony/notifier": "7.2.*",
"symfony/runtime": "7.2.*",
"symfony/translation": "7.2.*",
"symfony/twig-bundle": "7.2.*",
"symfony/yaml": "7.2.*",
"twig/extra-bundle": "^2.12|^3.20",
"twig/twig": "^2.12|^3.20"
},
"require-dev": {
"spatie/ray": "^1.41.5",
"symfony/maker-bundle": "^1.62.1",
"symfony/stopwatch": "7.2.*",
"symfony/web-profiler-bundle": "7.2.*"
},
"config": {
"allow-plugins": {
@@ -79,13 +85,8 @@
"extra": {
"symfony": {
"allow-contrib": false,
"require": "7.0.*"
"require": "7.2.*",
"docker": false
}
},
"require-dev": {
"spatie/ray": "^1.41",
"symfony/maker-bundle": "^1.58",
"symfony/stopwatch": "7.0.*",
"symfony/web-profiler-bundle": "7.0.*"
}
}
+7738 -3863
View File
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -10,7 +10,8 @@ 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],
];
+14 -3
View File
@@ -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
+3
View File
@@ -0,0 +1,3 @@
framework:
mailer:
dsn: '%env(MAILER_DSN)%'
@@ -1,33 +1,33 @@
nelmio_security:
# prevents framing of the entire site
clickjacking:
paths:
'^/.*': DENY
# disables content type sniffing for script resources
content_type:
nosniff: true
# forces Microsoft's XSS-Protection with
# its block mode
xss_protection:
enabled: true
mode_block: true
# Send a full URL in the `Referer` header when performing a same-origin request,
# only send the origin of the document to secure destination (HTTPS->HTTPS),
# and send no header to a less secure destination (HTTPS->HTTP).
# If `strict-origin-when-cross-origin` is not supported, use `no-referrer` policy,
# no referrer information is sent along with requests.
referrer_policy:
enabled: true
policies:
- 'no-referrer'
- 'strict-origin-when-cross-origin'
csp:
enabled: true
enforce:
script-src:
- 'self'
# nelmio_security:
# # prevents framing of the entire site
# clickjacking:
# paths:
# '^/.*': DENY
#
# # disables content type sniffing for script resources
# content_type:
# nosniff: true
#
# # forces Microsoft's XSS-Protection with
# # its block mode
# xss_protection:
# enabled: true
# mode_block: true
#
# # Send a full URL in the `Referer` header when performing a same-origin request,
# # only send the origin of the document to secure destination (HTTPS->HTTPS),
# # and send no header to a less secure destination (HTTPS->HTTP).
# # If `strict-origin-when-cross-origin` is not supported, use `no-referrer` policy,
# # no referrer information is sent along with requests.
# referrer_policy:
# enabled: true
# policies:
# - 'no-referrer'
# - 'strict-origin-when-cross-origin'
#
# csp:
# enabled: true
#
# enforce:
# script-src:
# - 'self'
@@ -0,0 +1,5 @@
twig_component:
anonymous_template_directory: 'components/'
defaults:
# Namespace & directory for components
App\Twig\Components\: 'components/'
@@ -1,6 +1,6 @@
when@dev:
web_profiler:
toolbar: true
toolbar: false
intercept_redirects: false
framework:
@@ -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)
});
});
}
});
@@ -0,0 +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){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}));
@@ -0,0 +1,2 @@
.notyf__icon--info,.notyf__icon--warning{background:#fff;border-radius:50%;box-sizing:border-box;display:block;height:1em;margin:0 auto;position:relative;width:1em}.notyf__icon--info:after,.notyf__icon--info:before,.notyf__icon--warning:after,.notyf__icon--warning:before{border-width:0;box-sizing:border-box;content:"";position:absolute;transition:all 1s}.notyf__icon--info:after,.notyf__icon--info:before{background-color:currentcolor;border-radius:.03em;left:50%;transform:translateX(-50%);width:.15em}.notyf__icon--info:before{height:.38em;top:.4em}.notyf__icon--info:after{box-shadow:-.06em .19em,-.06em .44em,.06em .44em;height:.13em;top:.21em}.notyf__icon--warning:after,.notyf__icon--warning:before{background-color:currentcolor;border-radius:.03em;left:50%;transform:translateX(-50%);width:.15em}.notyf__icon--warning:before{height:.38em;top:.21em}.notyf__icon--warning:after{height:.13em;top:.65em}
@keyframes notyf-fadeinup{0%{opacity:0;transform:translateY(25%)}to{opacity:1;transform:translateY(0)}}@keyframes notyf-fadeinleft{0%{opacity:0;transform:translateX(25%)}to{opacity:1;transform:translateX(0)}}@keyframes notyf-fadeoutright{0%{opacity:1;transform:translateX(0)}to{opacity:0;transform:translateX(25%)}}@keyframes notyf-fadeoutdown{0%{opacity:1;transform:translateY(0)}to{opacity:0;transform:translateY(25%)}}@keyframes ripple{0%{transform:scale(0) translateY(-45%) translateX(13%)}to{transform:scale(1) translateY(-45%) translateX(13%)}}.notyf{align-items:flex-end;box-sizing:border-box;color:#fff;display:flex;flex-direction:column;height:100%;justify-content:flex-end;left:0;padding:20px;pointer-events:none;position:fixed;top:0;width:100%;z-index:9999}.notyf__icon--error,.notyf__icon--success{background:#fff;border-radius:50%;display:block;height:21px;margin:0 auto;position:relative;width:21px}.notyf__icon--error:after,.notyf__icon--error:before{background:currentColor;border-radius:3px;content:"";display:block;height:12px;left:9px;position:absolute;top:5px;width:3px}.notyf__icon--error:after{transform:rotate(-45deg)}.notyf__icon--error:before{transform:rotate(45deg)}.notyf__icon--success:after,.notyf__icon--success:before{background:currentColor;border-radius:3px;content:"";display:block;position:absolute;width:3px}.notyf__icon--success:after{height:6px;left:6px;top:9px;transform:rotate(-45deg)}.notyf__icon--success:before{height:11px;left:10px;top:5px;transform:rotate(45deg)}.notyf__toast{animation:notyf-fadeinup .3s ease-in forwards;border-radius:2px;box-shadow:0 3px 7px 0 rgba(0,0,0,.25);box-sizing:border-box;display:block;flex-shrink:0;max-width:300px;overflow:hidden;padding:0 15px;pointer-events:auto;position:relative;transform:translateY(25%)}.notyf__toast--disappear{animation:notyf-fadeoutdown .3s forwards;animation-delay:.25s;transform:translateY(0)}.notyf__toast--disappear .notyf__icon,.notyf__toast--disappear .notyf__message{animation:notyf-fadeoutdown .3s forwards;opacity:1;transform:translateY(0)}.notyf__toast--disappear .notyf__dismiss{animation:notyf-fadeoutright .3s forwards;opacity:1;transform:translateX(0)}.notyf__toast--disappear .notyf__message{animation-delay:.05s}.notyf__toast--upper{margin-bottom:20px}.notyf__toast--lower{margin-top:20px}.notyf__toast--dismissible .notyf__wrapper{padding-right:30px}.notyf__ripple{animation:ripple .4s ease-out forwards;border-radius:50%;height:400px;position:absolute;right:0;top:0;transform:scale(0) translateY(-51%) translateX(13%);transform-origin:bottom right;width:400px;z-index:5}.notyf__wrapper{align-items:center;border-radius:3px;display:flex;padding-bottom:17px;padding-right:15px;padding-top:17px;position:relative;z-index:10}.notyf__icon{animation:notyf-fadeinup .3s forwards;animation-delay:.3s;font-size:1.3em;margin-right:13px;opacity:0;text-align:center;width:22px}.notyf__dismiss{animation:notyf-fadeinleft .3s forwards;animation-delay:.35s;height:100%;margin-right:-15px;opacity:0;position:absolute;right:0;top:0;width:26px}.notyf__dismiss-btn{background-color:rgba(0,0,0,.25);border:none;cursor:pointer;height:100%;opacity:.35;outline:none;transition:opacity .2s ease,background-color .2s ease;width:100%}.notyf__dismiss-btn:after,.notyf__dismiss-btn:before{background:#fff;border-radius:3px;content:"";height:12px;left:calc(50% - 1px);position:absolute;top:calc(50% - 5px);width:2px}.notyf__dismiss-btn:after{transform:rotate(-45deg)}.notyf__dismiss-btn:before{transform:rotate(45deg)}.notyf__dismiss-btn:hover{background-color:rgba(0,0,0,.15);opacity:.7}.notyf__dismiss-btn:active{opacity:.8}.notyf__message{animation:notyf-fadeinup .3s forwards;animation-delay:.25s;line-height:1.5em;opacity:0;position:relative;vertical-align:middle}@media only screen and (max-width:480px){.notyf{padding:0}.notyf__ripple{animation-duration:.5s;height:600px;width:600px}.notyf__toast{border-radius:0;box-shadow:0 -2px 7px 0 rgba(0,0,0,.13);max-width:none;width:100%}.notyf__dismiss{width:56px}}
File diff suppressed because one or more lines are too long
@@ -0,0 +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 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}));
@@ -0,0 +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){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}));
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+51
View File
@@ -0,0 +1,51 @@
{
"/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=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=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=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=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"
}
+37
View File
@@ -0,0 +1,37 @@
.noty_theme__mint.noty_bar {
margin: 4px 0;
overflow: hidden;
border-radius: 2px;
position: relative; }
.noty_theme__mint.noty_bar .noty_body {
padding: 10px;
font-size: 14px; }
.noty_theme__mint.noty_bar .noty_buttons {
padding: 10px; }
.noty_theme__mint.noty_type__alert,
.noty_theme__mint.noty_type__notification {
background-color: #fff;
border-bottom: 1px solid #D1D1D1;
color: #2F2F2F; }
.noty_theme__mint.noty_type__warning {
background-color: #FFAE42;
border-bottom: 1px solid #E89F3C;
color: #fff; }
.noty_theme__mint.noty_type__error {
background-color: #DE636F;
border-bottom: 1px solid #CA5A65;
color: #fff; }
.noty_theme__mint.noty_type__info,
.noty_theme__mint.noty_type__information {
background-color: #7F7EFF;
border-bottom: 1px solid #7473E8;
color: #fff; }
.noty_theme__mint.noty_type__success {
background-color: #AFC765;
border-bottom: 1px solid #A0B55C;
color: #fff; }
+216
View File
@@ -0,0 +1,216 @@
.noty_layout_mixin, #noty_layout__top, #noty_layout__topLeft, #noty_layout__topCenter, #noty_layout__topRight, #noty_layout__bottom, #noty_layout__bottomLeft, #noty_layout__bottomCenter, #noty_layout__bottomRight, #noty_layout__center, #noty_layout__centerLeft, #noty_layout__centerRight {
position: fixed;
margin: 0;
padding: 0;
z-index: 9999999;
-webkit-transform: translateZ(0) scale(1, 1);
transform: translateZ(0) scale(1, 1);
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
-webkit-font-smoothing: subpixel-antialiased;
filter: blur(0);
-webkit-filter: blur(0);
max-width: 90%; }
#noty_layout__top {
top: 0;
left: 5%;
width: 90%; }
#noty_layout__topLeft {
top: 20px;
left: 20px;
width: 325px; }
#noty_layout__topCenter {
top: 5%;
left: 50%;
width: 325px;
-webkit-transform: translate(-webkit-calc(-50% - .5px)) translateZ(0) scale(1, 1);
transform: translate(calc(-50% - .5px)) translateZ(0) scale(1, 1); }
#noty_layout__topRight {
top: 20px;
right: 20px;
width: 325px; }
#noty_layout__bottom {
bottom: 0;
left: 5%;
width: 90%; }
#noty_layout__bottomLeft {
bottom: 20px;
left: 20px;
width: 325px; }
#noty_layout__bottomCenter {
bottom: 5%;
left: 50%;
width: 325px;
-webkit-transform: translate(-webkit-calc(-50% - .5px)) translateZ(0) scale(1, 1);
transform: translate(calc(-50% - .5px)) translateZ(0) scale(1, 1); }
#noty_layout__bottomRight {
bottom: 20px;
right: 20px;
width: 325px; }
#noty_layout__center {
top: 50%;
left: 50%;
width: 325px;
-webkit-transform: translate(-webkit-calc(-50% - .5px), -webkit-calc(-50% - .5px)) translateZ(0) scale(1, 1);
transform: translate(calc(-50% - .5px), calc(-50% - .5px)) translateZ(0) scale(1, 1); }
#noty_layout__centerLeft {
top: 50%;
left: 20px;
width: 325px;
-webkit-transform: translate(0, -webkit-calc(-50% - .5px)) translateZ(0) scale(1, 1);
transform: translate(0, calc(-50% - .5px)) translateZ(0) scale(1, 1); }
#noty_layout__centerRight {
top: 50%;
right: 20px;
width: 325px;
-webkit-transform: translate(0, -webkit-calc(-50% - .5px)) translateZ(0) scale(1, 1);
transform: translate(0, calc(-50% - .5px)) translateZ(0) scale(1, 1); }
.noty_progressbar {
display: none; }
.noty_has_timeout.noty_has_progressbar .noty_progressbar {
display: block;
position: absolute;
left: 0;
bottom: 0;
height: 3px;
width: 100%;
background-color: #646464;
opacity: 0.2;
filter: alpha(opacity=10); }
.noty_bar {
-webkit-backface-visibility: hidden;
-webkit-transform: translate(0, 0) translateZ(0) scale(1, 1);
-ms-transform: translate(0, 0) scale(1, 1);
transform: translate(0, 0) scale(1, 1);
-webkit-font-smoothing: subpixel-antialiased;
overflow: hidden; }
.noty_effects_open {
opacity: 0;
-webkit-transform: translate(50%);
-ms-transform: translate(50%);
transform: translate(50%);
-webkit-animation: noty_anim_in 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55);
animation: noty_anim_in 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55);
-webkit-animation-fill-mode: forwards;
animation-fill-mode: forwards; }
.noty_effects_close {
-webkit-animation: noty_anim_out 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55);
animation: noty_anim_out 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55);
-webkit-animation-fill-mode: forwards;
animation-fill-mode: forwards; }
.noty_fix_effects_height {
-webkit-animation: noty_anim_height 75ms ease-out;
animation: noty_anim_height 75ms ease-out; }
.noty_close_with_click {
cursor: pointer; }
.noty_close_button {
position: absolute;
top: 2px;
right: 2px;
font-weight: bold;
width: 20px;
height: 20px;
text-align: center;
line-height: 20px;
background-color: rgba(0, 0, 0, 0.05);
border-radius: 2px;
cursor: pointer;
-webkit-transition: all .2s ease-out;
transition: all .2s ease-out; }
.noty_close_button:hover {
background-color: rgba(0, 0, 0, 0.1); }
.noty_modal {
position: fixed;
width: 100%;
height: 100%;
background-color: #000;
z-index: 10000;
opacity: .3;
left: 0;
top: 0; }
.noty_modal.noty_modal_open {
opacity: 0;
-webkit-animation: noty_modal_in .3s ease-out;
animation: noty_modal_in .3s ease-out; }
.noty_modal.noty_modal_close {
-webkit-animation: noty_modal_out .3s ease-out;
animation: noty_modal_out .3s ease-out;
-webkit-animation-fill-mode: forwards;
animation-fill-mode: forwards; }
@-webkit-keyframes noty_modal_in {
100% {
opacity: .3; } }
@keyframes noty_modal_in {
100% {
opacity: .3; } }
@-webkit-keyframes noty_modal_out {
100% {
opacity: 0; } }
@keyframes noty_modal_out {
100% {
opacity: 0; } }
@keyframes noty_modal_out {
100% {
opacity: 0; } }
@-webkit-keyframes noty_anim_in {
100% {
-webkit-transform: translate(0);
transform: translate(0);
opacity: 1; } }
@keyframes noty_anim_in {
100% {
-webkit-transform: translate(0);
transform: translate(0);
opacity: 1; } }
@-webkit-keyframes noty_anim_out {
100% {
-webkit-transform: translate(50%);
transform: translate(50%);
opacity: 0; } }
@keyframes noty_anim_out {
100% {
-webkit-transform: translate(50%);
transform: translate(50%);
opacity: 0; } }
@-webkit-keyframes noty_anim_height {
100% {
height: 0; } }
@keyframes noty_anim_height {
100% {
height: 0; } }
/*# sourceMappingURL=noty.css.map*/
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
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">&times;</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>`}})}));
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,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');
}
}
+65 -12
View File
@@ -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');
}
}

Some files were not shown because too many files have changed in this diff Show More