{% block page_title %}Welcome to PHPFlasher{% endblock %}
+{% block page_subtitle %}A powerful notification system for PHP applications{% endblock %}
+diff --git a/demo/symfony/config/bundles.php b/demo/symfony/config/bundles.php index d3436796..65ef1ce3 100644 --- a/demo/symfony/config/bundles.php +++ b/demo/symfony/config/bundles.php @@ -10,7 +10,7 @@ return [ Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true], Twig\Extra\TwigExtraBundle\TwigExtraBundle::class => ['all' => true], Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true], - Nelmio\SecurityBundle\NelmioSecurityBundle::class => ['all' => true], + // Nelmio\SecurityBundle\NelmioSecurityBundle::class => ['all' => true], Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true], Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true], Symfony\UX\TwigComponent\TwigComponentBundle::class => ['all' => true], diff --git a/demo/symfony/config/packages/flasher.yaml b/demo/symfony/config/packages/flasher.yaml index 970714c8..8ff4c75b 100644 --- a/demo/symfony/config/packages/flasher.yaml +++ b/demo/symfony/config/packages/flasher.yaml @@ -1,7 +1,7 @@ flasher: # Default notification library (e.g., 'flasher', 'toastr', 'noty', etc.) # themes: flasher, crystal, emerald, sapphire - default: theme.amazon + default: theme.minimal # Path to the main JavaScript file of PHPFlasher main_script: '/vendor/flasher/flasher.min.js' diff --git a/demo/symfony/config/packages/nelmio_security.yaml b/demo/symfony/config/packages/nelmio_security.yaml index 126b813d..08831bf9 100644 --- a/demo/symfony/config/packages/nelmio_security.yaml +++ b/demo/symfony/config/packages/nelmio_security.yaml @@ -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' diff --git a/demo/symfony/public/js/interactive-demo.js b/demo/symfony/public/js/interactive-demo.js new file mode 100644 index 00000000..a07e24ea --- /dev/null +++ b/demo/symfony/public/js/interactive-demo.js @@ -0,0 +1,22 @@ +document.addEventListener('DOMContentLoaded', function() { + const demoForm = document.getElementById('notification-demo-form'); + + if (demoForm) { + demoForm.addEventListener('submit', function(e) { + e.preventDefault(); + + const type = document.getElementById('notification-type').value; + const title = document.getElementById('notification-title').value; + const message = document.getElementById('notification-message').value; + const position = document.getElementById('notification-position').value; + const timeout = document.getElementById('notification-timeout').value; + + // Use the PHPFlasher JavaScript API to show the notification + window.flasher[type](message, { + title: title, + position: position, + timeout: parseInt(timeout, 10) + }); + }); + } +}); diff --git a/demo/symfony/src/Controller/ExamplesController.php b/demo/symfony/src/Controller/ExamplesController.php new file mode 100644 index 00000000..51adfb46 --- /dev/null +++ b/demo/symfony/src/Controller/ExamplesController.php @@ -0,0 +1,147 @@ +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]); + } +} diff --git a/demo/symfony/src/Controller/FeaturesController.php b/demo/symfony/src/Controller/FeaturesController.php new file mode 100644 index 00000000..47c6bb8d --- /dev/null +++ b/demo/symfony/src/Controller/FeaturesController.php @@ -0,0 +1,78 @@ +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'); + } +} diff --git a/demo/symfony/src/Controller/HomeController.php b/demo/symfony/src/Controller/HomeController.php index 2e92c0a0..19ee0646 100644 --- a/demo/symfony/src/Controller/HomeController.php +++ b/demo/symfony/src/Controller/HomeController.php @@ -5,6 +5,8 @@ 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; @@ -13,77 +15,68 @@ class HomeController extends AbstractController #[Route('/', name: 'app_home')] public function index(): Response { - $themes = [ - // 'flasher', - // 'amber', - // 'sapphire', - // 'crystal', - - // 'emerald', - // 'ruby', - // 'onyx', - - // 'jade', - // 'aurora', - // 'neon', - // 'minimal', - - // 'material', - // 'google', - - // 'ios', - // 'slack', - // 'facebook', - // 'amazon', - ]; - - $positions = [ - // 'top-left', - // 'top-right', - // 'bottom-left', - // 'bottom-right', - // 'top-center', - // 'bottom-center', - // 'center-left', - // 'center-right', - // 'center-center', - ]; - - $messages = [ - 'info' => 'Welcome back!', - 'warning' => 'Are you sure you want to proceed?', - 'error' => 'Oops! Something went wrong!', - 'success' => 'Data has been saved successfully!', - ]; - - // foreach ($themes as $index => $theme) { - foreach ($messages as $type => $message) { - // $position = $positions[$index % \count($positions)]; - - // $message = \sprintf('%s: %s', $theme, $message); - - flash() - // ->use("theme.$theme") - // ->option('position', $position) - ->$type($message); - } - // } - - $plugins = [ - // 'noty', - // 'notyf', - // 'sweetalert', - // 'toastr', - ]; - - foreach ($plugins as $plugin) { - foreach ($messages as $type => $message) { - flash() - ->use($plugin) - ->$type($message); - } - } + // 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']); + } } diff --git a/demo/symfony/src/Controller/IntegrationController.php b/demo/symfony/src/Controller/IntegrationController.php new file mode 100644 index 00000000..e31bf1fa --- /dev/null +++ b/demo/symfony/src/Controller/IntegrationController.php @@ -0,0 +1,53 @@ +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'); + } +} diff --git a/demo/symfony/src/Controller/ThemesController.php b/demo/symfony/src/Controller/ThemesController.php new file mode 100644 index 00000000..ecd9c160 --- /dev/null +++ b/demo/symfony/src/Controller/ThemesController.php @@ -0,0 +1,71 @@ +success('This is a notification with the default theme!'); + + return $this->render('themes/index.html.twig'); + } + + #[Route('/themes/flasher', name: 'app_theme_flasher')] + public function flasherTheme(): Response + { + // Using the Flasher theme + flash()->option('theme', 'flasher') + ->success('This notification uses the Flasher theme!'); + + return $this->render('themes/flasher.html.twig'); + } + + #[Route('/themes/crystal', name: 'app_theme_crystal')] + public function crystalTheme(): Response + { + // Using the Crystal theme + flash()->option('theme', 'crystal') + ->success('This notification uses the Crystal theme!'); + + return $this->render('themes/crystal.html.twig'); + } + + #[Route('/themes/emerald', name: 'app_theme_emerald')] + public function emeraldTheme(): Response + { + // Using the Emerald theme + flash()->option('theme', 'emerald') + ->success('This notification uses the Emerald theme!'); + + return $this->render('themes/emerald.html.twig'); + } + + #[Route('/themes/sapphire', name: 'app_theme_sapphire')] + public function sapphireTheme(): Response + { + // Using the Sapphire theme + flash()->option('theme', 'sapphire') + ->success('This notification uses the Sapphire theme!'); + + return $this->render('themes/sapphire.html.twig'); + } + + #[Route('/themes/amazon', name: 'app_theme_amazon')] + public function amazonTheme(): Response + { + // Using the Amazon theme + flash()->option('theme', 'amazon') + ->success('This notification uses the Amazon theme!'); + + return $this->render('themes/amazon.html.twig'); + } +} diff --git a/demo/symfony/templates/base.html.twig b/demo/symfony/templates/base.html.twig index 5312acde..a8253e89 100644 --- a/demo/symfony/templates/base.html.twig +++ b/demo/symfony/templates/base.html.twig @@ -1,17 +1,231 @@ - -
-{% block page_subtitle %}A powerful notification system for PHP applications{% endblock %}
++ PHPFlasher allows you to position your notifications in different areas of the screen. + You can choose from 9 different positions to best fit your design and user experience needs. +
+ +
+ You can set the position of notifications in your PHP code using the option() method:
+
// Top-right position (default)
+flash()->success('Your changes have been saved.');
+
+// Bottom-left position
+flash()->option('position', 'bottom-left')
+ ->success('Your changes have been saved.');
+
+// Top-center position
+flash()->option('position', 'top-center')
+ ->info('You have 3 unread messages.');
+
+// Center position (middle of the screen)
+flash()->option('position', 'center')
+ ->warning('Your session will expire in 1 minute.');
+ + You can set a default position for all notifications in your configuration file: +
+ +# config/packages/flasher.yaml
+flasher:
+ options:
+ position: 'top-right' # Default position for all notifications
+ + Or you can set specific positions for different themes: +
+ +# config/packages/flasher.yaml
+flasher:
+ themes:
+ amazon:
+ options:
+ position: 'bottom-right'
+
+ sapphire:
+ options:
+ position: 'top-center'
+ + PHPFlasher provides four primary notification types to communicate different types of messages to your users. + Each type has a distinct visual style to clearly convey the nature of the message. +
+ ++ Used for positive feedback when an action has been completed successfully. +
+flash()->success('Your profile has been updated successfully!');
+ + Used to alert users about errors or problems that need attention. +
+flash()->error('An error occurred while processing your request.');
+ + Used to inform users about potential issues or actions they should be aware of. +
+flash()->warning('Your subscription will expire in 3 days.');
+ + Used to provide neutral information or updates to users. +
+flash()->info('You have 5 unread messages.');
+ + Here's how you can use notification types in your Symfony controllers: +
+ +success('Form submitted successfully!');
+ } else {
+ // Show error notification
+ flash()->error('An error occurred while processing the form.');
+ }
+
+ // Show info notification
+ flash()->info('You will receive a confirmation email shortly.');
+
+ // Show warning notification
+ flash()->warning('Please verify your email within 24 hours.');
+
+ return $this->redirectToRoute('app_home');
+ }
+}
+ + You can combine notification types with other options to create more customized notifications: +
+ +// Success notification with custom timeout
+flash()->option('timeout', 8000)
+ ->success('Changes saved successfully!');
+
+// Warning notification with custom position
+flash()->option('position', 'bottom-center')
+ ->warning('Your session will expire soon.');
+
+// Error notification with progress bar
+flash()->option('showProgressbar', true)
+ ->error('Unable to connect to the server.');
+ Display success, error, warning, and info notifications to communicate different messages to your users.
+ +Place notifications in different positions around the screen to best suit your UI design.
+ +Customize timeouts, animations, progressbars, and more with PHPFlasher's flexible configuration.
+PHPFlasher can be extended with plugins to add more functionality.
+Create reusable notification configurations for consistent messaging.
+Want to experiment with different notification settings? Use our interactive playground to test PHPFlasher's features in real-time.
++ PHPFlasher comes with various themes to help you match the notification style to your application's design. + Each theme provides a distinct visual appearance while maintaining the same functionality. +
+ +Flasher Default Theme
+Clean and minimal design
+The default theme with a clean, minimal design that works well in most applications.
+ +Emerald Theme
+Elegant left-border style
+A sleek theme with colored left borders and subtle design elements.
+ +Sapphire Theme
+Modern with rounded icons
+A modern theme with rounded icons and smooth animations.
+ +Crystal Theme
+Transparent with blur effects
+A modern glass-like theme with transparency and blur effects.
+ +Amazon Theme
+Inspired by Amazon's notification style
+Inspired by Amazon's notification style with distinctive icons.
+ +
+ You can specify which theme to use for each notification using the option() method:
+
// Using the default theme
+flash()->success('Your profile has been updated successfully!');
+
+// Using the Emerald theme
+flash()->option('theme', 'emerald')
+ ->success('Your profile has been updated successfully!');
+
+// Using the Sapphire theme with additional options
+flash()->option('theme', 'sapphire')
+ ->option('position', 'bottom-right')
+ ->option('timeout', 5000)
+ ->info('You have 3 unread messages.');
+
+// Using the Amazon theme
+flash()->option('theme', 'amazon')
+ ->warning('Your subscription will expire in 3 days.');
+ + You can configure themes globally in your configuration file: +
+ +# config/packages/flasher.yaml
+flasher:
+ # Set the default theme for all notifications
+ default: theme.amazon
+
+ themes:
+ amazon:
+ scripts:
+ - '/vendor/flasher/themes/amazon/amazon.min.js'
+ styles:
+ - '/vendor/flasher/flasher.min.css'
+ - '/vendor/flasher/themes/amazon/amazon.min.css'
+ options:
+ position: 'bottom-right'
+ timeout: 6000
+
+ emerald:
+ scripts:
+ - '/vendor/flasher/themes/emerald/emerald.min.js'
+ styles:
+ - '/vendor/flasher/flasher.min.css'
+ - '/vendor/flasher/themes/emerald/emerald.min.css'
+ options:
+ position: 'top-right'
+ timeout: 5000
+ + Each theme can have its own default options, scripts, and styles. This allows you to create a consistent notification experience throughout your application. +
++ Need something more customized? PHPFlasher allows you to create your own themes: +
+ +# config/packages/flasher.yaml
+flasher:
+ themes:
+ custom_theme:
+ scripts:
+ - '/assets/js/custom-theme.js'
+ styles:
+ - '/assets/css/custom-theme.css'
+ options:
+ position: 'top-center'
+ timeout: 7000
+ # Add any custom options your theme supports
+ + Then you can use your custom theme in your code: +
+ +flash()->option('theme', 'custom_theme')
+ ->success('This uses your custom theme!');
+