mirror of
https://github.com/php-flasher/php-flasher.git
synced 2026-03-31 15:07:47 +01:00
Revamp Flasher demo application
This commit is contained in:
@@ -0,0 +1,192 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\View\View;
|
||||
|
||||
final class DemoController extends Controller
|
||||
{
|
||||
public function home(): View
|
||||
{
|
||||
return view('home');
|
||||
}
|
||||
|
||||
public function types(): View
|
||||
{
|
||||
return view('types');
|
||||
}
|
||||
|
||||
public function themes(): View
|
||||
{
|
||||
return view('themes');
|
||||
}
|
||||
|
||||
public function adapters(): View
|
||||
{
|
||||
return view('adapters');
|
||||
}
|
||||
|
||||
public function positions(): View
|
||||
{
|
||||
return view('positions');
|
||||
}
|
||||
|
||||
public function examples(): View
|
||||
{
|
||||
return view('examples');
|
||||
}
|
||||
|
||||
public function playground(): View
|
||||
{
|
||||
return view('playground');
|
||||
}
|
||||
|
||||
public function livewire(): View
|
||||
{
|
||||
return view('livewire');
|
||||
}
|
||||
|
||||
public function notify(Request $request): JsonResponse
|
||||
{
|
||||
$type = $request->input('type', 'success');
|
||||
$message = $request->input('message', 'Notification message');
|
||||
$title = $request->input('title');
|
||||
$theme = $request->input('theme', 'flasher');
|
||||
$adapter = $request->input('adapter', 'flasher');
|
||||
$position = $request->input('position', 'top-right');
|
||||
$timeout = (int) $request->input('timeout', 5000);
|
||||
|
||||
$flasher = match ($adapter) {
|
||||
'toastr' => toastr(),
|
||||
'sweetalert' => sweetalert(),
|
||||
'noty' => noty(),
|
||||
'notyf' => notyf(),
|
||||
default => flash()->use("theme.{$theme}"),
|
||||
};
|
||||
|
||||
$options = [
|
||||
'position' => $position,
|
||||
'timeout' => $timeout,
|
||||
];
|
||||
|
||||
if ($adapter === 'toastr') {
|
||||
$options['positionClass'] = 'toast-' . str_replace('-', '-', $position);
|
||||
$options['timeOut'] = $timeout;
|
||||
} elseif ($adapter === 'noty') {
|
||||
$options['layout'] = match ($position) {
|
||||
'top-right' => 'topRight',
|
||||
'top-left' => 'topLeft',
|
||||
'top-center' => 'topCenter',
|
||||
'bottom-right' => 'bottomRight',
|
||||
'bottom-left' => 'bottomLeft',
|
||||
'bottom-center' => 'bottomCenter',
|
||||
default => 'topRight',
|
||||
};
|
||||
$options['timeout'] = $timeout;
|
||||
} elseif ($adapter === 'notyf') {
|
||||
$positionParts = explode('-', $position);
|
||||
$options['position'] = [
|
||||
'y' => $positionParts[0] ?? 'top',
|
||||
'x' => $positionParts[1] ?? 'right',
|
||||
];
|
||||
$options['duration'] = $timeout;
|
||||
}
|
||||
|
||||
if ($title) {
|
||||
$flasher->{$type}($message, $title, $options);
|
||||
} else {
|
||||
$flasher->{$type}($message, $options);
|
||||
}
|
||||
|
||||
return response()->json(['success' => true]);
|
||||
}
|
||||
|
||||
public function runExample(Request $request, string $scenario): JsonResponse
|
||||
{
|
||||
match ($scenario) {
|
||||
'registration' => $this->registrationExample(),
|
||||
'login_failed' => $this->loginFailedExample(),
|
||||
'validation' => $this->validationExample(),
|
||||
'shopping_cart' => $this->shoppingCartExample(),
|
||||
'file_upload' => $this->fileUploadExample(),
|
||||
'settings' => $this->settingsExample(),
|
||||
'payment_success' => $this->paymentSuccessExample(),
|
||||
'payment_failed' => $this->paymentFailedExample(),
|
||||
'delete_confirm' => $this->deleteConfirmExample(),
|
||||
'session_expiring' => $this->sessionExpiringExample(),
|
||||
default => flash()->info('Example not found'),
|
||||
};
|
||||
|
||||
return response()->json(['success' => true]);
|
||||
}
|
||||
|
||||
private function registrationExample(): void
|
||||
{
|
||||
flash()->success('Welcome! Your account has been created.');
|
||||
flash()->info('Please check your email to verify your account.');
|
||||
}
|
||||
|
||||
private function loginFailedExample(): void
|
||||
{
|
||||
flash()->error('Invalid email or password.');
|
||||
flash()->info('Forgot your password? Click here to reset.');
|
||||
}
|
||||
|
||||
private function validationExample(): void
|
||||
{
|
||||
flash()->error('The email field is required.');
|
||||
flash()->error('Password must be at least 8 characters.');
|
||||
flash()->error('Please accept the terms and conditions.');
|
||||
}
|
||||
|
||||
private function shoppingCartExample(): void
|
||||
{
|
||||
flash()->success('iPhone 15 Pro added to cart!');
|
||||
flash()->warning('Only 2 items left in stock!');
|
||||
flash()->info('Add $20 more for free shipping!');
|
||||
}
|
||||
|
||||
private function fileUploadExample(): void
|
||||
{
|
||||
flash()->success('document.pdf uploaded successfully!');
|
||||
flash()->info('File size: 2.4 MB');
|
||||
}
|
||||
|
||||
private function settingsExample(): void
|
||||
{
|
||||
flash()->success('Settings saved successfully!');
|
||||
flash()->info('Some changes may require a page refresh.');
|
||||
}
|
||||
|
||||
private function paymentSuccessExample(): void
|
||||
{
|
||||
flash()->success('Payment of $149.99 confirmed!');
|
||||
flash()->info('Order #12345 - Receipt sent to your email.');
|
||||
}
|
||||
|
||||
private function paymentFailedExample(): void
|
||||
{
|
||||
flash()->error('Payment declined by your bank.');
|
||||
flash()->warning('Please try a different payment method.');
|
||||
flash()->info('Your cart has been saved.');
|
||||
}
|
||||
|
||||
private function deleteConfirmExample(): void
|
||||
{
|
||||
sweetalert()
|
||||
->showCancelButton()
|
||||
->confirmButtonText('Yes, delete it!')
|
||||
->cancelButtonText('Cancel')
|
||||
->warning('Are you sure? This cannot be undone.');
|
||||
}
|
||||
|
||||
private function sessionExpiringExample(): void
|
||||
{
|
||||
flash()->warning('Your session will expire in 5 minutes.');
|
||||
flash()->info('Click anywhere to stay logged in.');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Livewire;
|
||||
|
||||
use Livewire\Component;
|
||||
|
||||
class ContactForm extends Component
|
||||
{
|
||||
public string $name = '';
|
||||
public string $email = '';
|
||||
public string $message = '';
|
||||
|
||||
protected array $rules = [
|
||||
'name' => 'required|min:2',
|
||||
'email' => 'required|email',
|
||||
'message' => 'required|min:10',
|
||||
];
|
||||
|
||||
public function submit(): void
|
||||
{
|
||||
$this->validate();
|
||||
|
||||
// Simulate form processing
|
||||
flash()->success('Message sent successfully!');
|
||||
flash()->info('We will respond within 24 hours.');
|
||||
|
||||
$this->reset(['name', 'email', 'message']);
|
||||
}
|
||||
|
||||
public function render()
|
||||
{
|
||||
return view('livewire.contact-form');
|
||||
}
|
||||
}
|
||||
@@ -1,25 +1,31 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Livewire;
|
||||
|
||||
use Livewire\Component;
|
||||
|
||||
class Counter extends Component
|
||||
{
|
||||
public $count = 1;
|
||||
public int $count = 0;
|
||||
|
||||
public function increment()
|
||||
public function increment(): void
|
||||
{
|
||||
flash()->success('increment');
|
||||
|
||||
$this->count++;
|
||||
flash()->success("Count increased to {$this->count}!");
|
||||
}
|
||||
|
||||
public function decrement()
|
||||
public function decrement(): void
|
||||
{
|
||||
flash()->info('decrement');
|
||||
|
||||
$this->count--;
|
||||
flash()->warning("Count decreased to {$this->count}");
|
||||
}
|
||||
|
||||
public function reset(): void
|
||||
{
|
||||
$this->count = 0;
|
||||
flash()->info('Counter has been reset.');
|
||||
}
|
||||
|
||||
public function render()
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Livewire;
|
||||
|
||||
use Livewire\Component;
|
||||
|
||||
class DeleteItem extends Component
|
||||
{
|
||||
protected $listeners = [
|
||||
'sweetalert:confirmed' => 'onConfirmed',
|
||||
'sweetalert:denied' => 'onDenied',
|
||||
];
|
||||
|
||||
public function confirmDelete(): void
|
||||
{
|
||||
sweetalert()
|
||||
->showDenyButton()
|
||||
->showCancelButton()
|
||||
->confirmButtonText('Yes, delete it!')
|
||||
->denyButtonText('Keep it')
|
||||
->warning('Are you sure you want to delete this item?');
|
||||
}
|
||||
|
||||
public function onConfirmed(array $payload): void
|
||||
{
|
||||
// Simulate deletion
|
||||
flash()->success('Item has been deleted successfully!');
|
||||
}
|
||||
|
||||
public function onDenied(array $payload): void
|
||||
{
|
||||
flash()->info('The item was kept safe.');
|
||||
}
|
||||
|
||||
public function render()
|
||||
{
|
||||
return view('livewire.delete-item');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,354 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Adapters')
|
||||
|
||||
@section('content')
|
||||
<div class="mb-8">
|
||||
<h1 class="section-title">Notification Adapters</h1>
|
||||
<p class="section-subtitle">PHPFlasher supports multiple notification libraries. Choose your favorite!</p>
|
||||
</div>
|
||||
|
||||
<div class="space-y-8">
|
||||
{{-- Flasher (Default) --}}
|
||||
<div class="card">
|
||||
<div class="h-2 bg-gradient-to-r from-indigo-500 to-purple-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex flex-col lg:flex-row lg:items-start lg:justify-between gap-6">
|
||||
<div class="flex-1">
|
||||
<div class="flex items-center space-x-3 mb-4">
|
||||
<div class="p-3 bg-indigo-100 rounded-xl">
|
||||
<svg class="w-8 h-8 text-indigo-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="text-2xl font-bold text-gray-800">Flasher</h2>
|
||||
<p class="text-gray-500">Default adapter with 17+ themes</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 mb-4">The default PHPFlasher adapter with beautiful built-in themes. No additional JavaScript libraries required.</p>
|
||||
|
||||
<div class="flex flex-wrap gap-2 mb-6">
|
||||
<button onclick="showNotification({type: 'success', message: 'This is the default Flasher notification!', adapter: 'flasher'})"
|
||||
class="btn btn-success">Success</button>
|
||||
<button onclick="showNotification({type: 'error', message: 'Error notification with Flasher', adapter: 'flasher'})"
|
||||
class="btn btn-danger">Error</button>
|
||||
<button onclick="showNotification({type: 'warning', message: 'Warning notification with Flasher', adapter: 'flasher'})"
|
||||
class="btn btn-warning">Warning</button>
|
||||
<button onclick="showNotification({type: 'info', message: 'Info notification with Flasher', adapter: 'flasher'})"
|
||||
class="btn btn-info">Info</button>
|
||||
</div>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>Installation</span>
|
||||
</div>
|
||||
<pre class="!m-0"><code class="language-bash">composer require php-flasher/flasher-laravel</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>Usage</span>
|
||||
</div>
|
||||
<pre class="!m-0"><code class="language-php">flash()->success('Operation completed!');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Toastr --}}
|
||||
<div class="card">
|
||||
<div class="h-2 bg-gradient-to-r from-sky-500 to-blue-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex flex-col lg:flex-row lg:items-start lg:justify-between gap-6">
|
||||
<div class="flex-1">
|
||||
<div class="flex items-center space-x-3 mb-4">
|
||||
<div class="p-3 bg-sky-100 rounded-xl">
|
||||
<svg class="w-8 h-8 text-sky-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="text-2xl font-bold text-gray-800">Toastr</h2>
|
||||
<p class="text-gray-500">Simple, elegant toast notifications</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 mb-4">Classic toast notifications with smooth animations. One of the most popular notification libraries.</p>
|
||||
|
||||
<div class="flex flex-wrap gap-2 mb-6">
|
||||
<button onclick="showNotification({type: 'success', message: 'Toastr success notification!', adapter: 'toastr'})"
|
||||
class="btn btn-success">Success</button>
|
||||
<button onclick="showNotification({type: 'error', message: 'Toastr error notification!', adapter: 'toastr'})"
|
||||
class="btn btn-danger">Error</button>
|
||||
<button onclick="showNotification({type: 'warning', message: 'Toastr warning notification!', adapter: 'toastr'})"
|
||||
class="btn btn-warning">Warning</button>
|
||||
<button onclick="showNotification({type: 'info', message: 'Toastr info notification!', adapter: 'toastr'})"
|
||||
class="btn btn-info">Info</button>
|
||||
</div>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>Installation</span>
|
||||
</div>
|
||||
<pre class="!m-0"><code class="language-bash">composer require php-flasher/flasher-toastr-laravel</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>Usage</span>
|
||||
</div>
|
||||
<pre class="!m-0"><code class="language-php">toastr()->success('Data saved successfully!');
|
||||
|
||||
// With options
|
||||
toastr()
|
||||
->closeButton()
|
||||
->progressBar()
|
||||
->positionClass('toast-top-right')
|
||||
->success('Profile updated!');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- SweetAlert --}}
|
||||
<div class="card">
|
||||
<div class="h-2 bg-gradient-to-r from-pink-500 to-rose-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex flex-col lg:flex-row lg:items-start lg:justify-between gap-6">
|
||||
<div class="flex-1">
|
||||
<div class="flex items-center space-x-3 mb-4">
|
||||
<div class="p-3 bg-pink-100 rounded-xl">
|
||||
<svg class="w-8 h-8 text-pink-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="text-2xl font-bold text-gray-800">SweetAlert 2</h2>
|
||||
<p class="text-gray-500">Beautiful, responsive, customizable alerts</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 mb-4">Feature-rich modal dialogs with confirmations, inputs, and beautiful animations. Perfect for important user interactions.</p>
|
||||
|
||||
<div class="flex flex-wrap gap-2 mb-6">
|
||||
<button onclick="showNotification({type: 'success', message: 'SweetAlert success!', title: 'Success', adapter: 'sweetalert'})"
|
||||
class="btn btn-success">Success</button>
|
||||
<button onclick="showNotification({type: 'error', message: 'SweetAlert error message', title: 'Error', adapter: 'sweetalert'})"
|
||||
class="btn btn-danger">Error</button>
|
||||
<button onclick="showNotification({type: 'warning', message: 'Are you sure you want to proceed?', title: 'Warning', adapter: 'sweetalert', options: {showCancelButton: true}})"
|
||||
class="btn btn-warning">Confirm Dialog</button>
|
||||
<button onclick="showNotification({type: 'info', message: 'Here is some information', title: 'Info', adapter: 'sweetalert'})"
|
||||
class="btn btn-info">Info</button>
|
||||
</div>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>Installation</span>
|
||||
</div>
|
||||
<pre class="!m-0"><code class="language-bash">composer require php-flasher/flasher-sweetalert-laravel</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>Usage</span>
|
||||
</div>
|
||||
<pre class="!m-0"><code class="language-php">sweetalert()->success('Great job!', 'Success');
|
||||
|
||||
// Confirmation dialog
|
||||
sweetalert()
|
||||
->showDenyButton()
|
||||
->showCancelButton()
|
||||
->confirmButtonText('Save')
|
||||
->denyButtonText("Don't save")
|
||||
->warning('Do you want to save the changes?');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Noty --}}
|
||||
<div class="card">
|
||||
<div class="h-2 bg-gradient-to-r from-emerald-500 to-teal-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex flex-col lg:flex-row lg:items-start lg:justify-between gap-6">
|
||||
<div class="flex-1">
|
||||
<div class="flex items-center space-x-3 mb-4">
|
||||
<div class="p-3 bg-emerald-100 rounded-xl">
|
||||
<svg class="w-8 h-8 text-emerald-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="text-2xl font-bold text-gray-800">Noty</h2>
|
||||
<p class="text-gray-500">Dependency-free notification library</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 mb-4">A flexible, dependency-free notification library with multiple layouts and themes.</p>
|
||||
|
||||
<div class="flex flex-wrap gap-2 mb-6">
|
||||
<button onclick="showNotification({type: 'success', message: 'Noty success notification!', adapter: 'noty'})"
|
||||
class="btn btn-success">Success</button>
|
||||
<button onclick="showNotification({type: 'error', message: 'Noty error notification!', adapter: 'noty'})"
|
||||
class="btn btn-danger">Error</button>
|
||||
<button onclick="showNotification({type: 'warning', message: 'Noty warning notification!', adapter: 'noty'})"
|
||||
class="btn btn-warning">Warning</button>
|
||||
<button onclick="showNotification({type: 'info', message: 'Noty info notification!', adapter: 'noty'})"
|
||||
class="btn btn-info">Info</button>
|
||||
</div>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>Installation</span>
|
||||
</div>
|
||||
<pre class="!m-0"><code class="language-bash">composer require php-flasher/flasher-noty-laravel</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>Usage</span>
|
||||
</div>
|
||||
<pre class="!m-0"><code class="language-php">noty()->success('Data saved!');
|
||||
|
||||
// With layout options
|
||||
noty()
|
||||
->layout('topCenter')
|
||||
->timeout(3000)
|
||||
->progressBar()
|
||||
->info('Processing your request...');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Notyf --}}
|
||||
<div class="card">
|
||||
<div class="h-2 bg-gradient-to-r from-amber-500 to-orange-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex flex-col lg:flex-row lg:items-start lg:justify-between gap-6">
|
||||
<div class="flex-1">
|
||||
<div class="flex items-center space-x-3 mb-4">
|
||||
<div class="p-3 bg-amber-100 rounded-xl">
|
||||
<svg class="w-8 h-8 text-amber-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 7h8m0 0v8m0-8l-8 8-4-4-6 6"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="text-2xl font-bold text-gray-800">Notyf</h2>
|
||||
<p class="text-gray-500">Minimalist, responsive notifications</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 mb-4">A minimalist JavaScript library for toast notifications. Tiny footprint with smooth animations.</p>
|
||||
|
||||
<div class="flex flex-wrap gap-2 mb-6">
|
||||
<button onclick="showNotification({type: 'success', message: 'Notyf success notification!', adapter: 'notyf'})"
|
||||
class="btn btn-success">Success</button>
|
||||
<button onclick="showNotification({type: 'error', message: 'Notyf error notification!', adapter: 'notyf'})"
|
||||
class="btn btn-danger">Error</button>
|
||||
</div>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>Installation</span>
|
||||
</div>
|
||||
<pre class="!m-0"><code class="language-bash">composer require php-flasher/flasher-notyf-laravel</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>Usage</span>
|
||||
</div>
|
||||
<pre class="!m-0"><code class="language-php">notyf()->success('Minimal and clean!');
|
||||
|
||||
// With options
|
||||
notyf()
|
||||
->position('x', 'right')
|
||||
->position('y', 'top')
|
||||
->dismissible(true)
|
||||
->ripple(true)
|
||||
->success('File uploaded successfully!');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Comparison Table --}}
|
||||
<div class="card mt-8">
|
||||
<div class="card-header">
|
||||
<h2 class="text-xl font-bold text-gray-800">Adapter Comparison</h2>
|
||||
</div>
|
||||
<div class="card-body overflow-x-auto">
|
||||
<table class="w-full text-left">
|
||||
<thead>
|
||||
<tr class="border-b border-gray-200">
|
||||
<th class="py-3 px-4 font-semibold text-gray-700">Feature</th>
|
||||
<th class="py-3 px-4 font-semibold text-gray-700">Flasher</th>
|
||||
<th class="py-3 px-4 font-semibold text-gray-700">Toastr</th>
|
||||
<th class="py-3 px-4 font-semibold text-gray-700">SweetAlert</th>
|
||||
<th class="py-3 px-4 font-semibold text-gray-700">Noty</th>
|
||||
<th class="py-3 px-4 font-semibold text-gray-700">Notyf</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="text-gray-600">
|
||||
<tr class="border-b border-gray-100">
|
||||
<td class="py-3 px-4">Toast Notifications</td>
|
||||
<td class="py-3 px-4 text-emerald-600">Yes</td>
|
||||
<td class="py-3 px-4 text-emerald-600">Yes</td>
|
||||
<td class="py-3 px-4 text-emerald-600">Yes</td>
|
||||
<td class="py-3 px-4 text-emerald-600">Yes</td>
|
||||
<td class="py-3 px-4 text-emerald-600">Yes</td>
|
||||
</tr>
|
||||
<tr class="border-b border-gray-100">
|
||||
<td class="py-3 px-4">Modal Dialogs</td>
|
||||
<td class="py-3 px-4 text-gray-400">No</td>
|
||||
<td class="py-3 px-4 text-gray-400">No</td>
|
||||
<td class="py-3 px-4 text-emerald-600">Yes</td>
|
||||
<td class="py-3 px-4 text-gray-400">No</td>
|
||||
<td class="py-3 px-4 text-gray-400">No</td>
|
||||
</tr>
|
||||
<tr class="border-b border-gray-100">
|
||||
<td class="py-3 px-4">Confirmations</td>
|
||||
<td class="py-3 px-4 text-gray-400">No</td>
|
||||
<td class="py-3 px-4 text-gray-400">No</td>
|
||||
<td class="py-3 px-4 text-emerald-600">Yes</td>
|
||||
<td class="py-3 px-4 text-emerald-600">Yes</td>
|
||||
<td class="py-3 px-4 text-gray-400">No</td>
|
||||
</tr>
|
||||
<tr class="border-b border-gray-100">
|
||||
<td class="py-3 px-4">Progress Bar</td>
|
||||
<td class="py-3 px-4 text-emerald-600">Yes</td>
|
||||
<td class="py-3 px-4 text-emerald-600">Yes</td>
|
||||
<td class="py-3 px-4 text-emerald-600">Yes</td>
|
||||
<td class="py-3 px-4 text-emerald-600">Yes</td>
|
||||
<td class="py-3 px-4 text-gray-400">No</td>
|
||||
</tr>
|
||||
<tr class="border-b border-gray-100">
|
||||
<td class="py-3 px-4">Built-in Themes</td>
|
||||
<td class="py-3 px-4 text-emerald-600">17+</td>
|
||||
<td class="py-3 px-4 text-emerald-600">4</td>
|
||||
<td class="py-3 px-4 text-emerald-600">1</td>
|
||||
<td class="py-3 px-4 text-emerald-600">5</td>
|
||||
<td class="py-3 px-4 text-emerald-600">1</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="py-3 px-4">Dependencies</td>
|
||||
<td class="py-3 px-4">None</td>
|
||||
<td class="py-3 px-4">jQuery</td>
|
||||
<td class="py-3 px-4">None</td>
|
||||
<td class="py-3 px-4">None</td>
|
||||
<td class="py-3 px-4">None</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,349 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Real-World Examples')
|
||||
|
||||
@section('content')
|
||||
<div class="mb-8">
|
||||
<h1 class="section-title">Real-World Examples</h1>
|
||||
<p class="section-subtitle">See how PHPFlasher handles common application scenarios. Click to run each example.</p>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||
{{-- User Registration --}}
|
||||
<div class="card">
|
||||
<div class="h-2 bg-gradient-to-r from-emerald-500 to-green-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center space-x-3 mb-4">
|
||||
<div class="p-3 bg-emerald-100 rounded-xl">
|
||||
<svg class="w-6 h-6 text-emerald-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M18 9v3m0 0v3m0-3h3m-3 0h-3m-2-5a4 4 0 11-8 0 4 4 0 018 0zM3 20a6 6 0 0112 0v1H3v-1z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-lg font-bold text-gray-800">User Registration</h3>
|
||||
<p class="text-sm text-gray-500">Account creation flow</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 mb-4">Simulates a successful user registration with welcome message and email verification notice.</p>
|
||||
|
||||
<button onclick="runExample('registration')" class="btn btn-success w-full mb-4">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"></path>
|
||||
</svg>
|
||||
Run Example
|
||||
</button>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header"><span>PHP</span></div>
|
||||
<pre class="!m-0"><code class="language-php">flash()->success('Welcome! Your account has been created.');
|
||||
flash()->info('Please check your email to verify your account.');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Login Flow --}}
|
||||
<div class="card">
|
||||
<div class="h-2 bg-gradient-to-r from-rose-500 to-red-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center space-x-3 mb-4">
|
||||
<div class="p-3 bg-rose-100 rounded-xl">
|
||||
<svg class="w-6 h-6 text-rose-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-lg font-bold text-gray-800">Login Failed</h3>
|
||||
<p class="text-sm text-gray-500">Authentication error</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 mb-4">Shows how to display login failure messages with helpful guidance.</p>
|
||||
|
||||
<button onclick="runExample('login_failed')" class="btn btn-danger w-full mb-4">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"></path>
|
||||
</svg>
|
||||
Run Example
|
||||
</button>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header"><span>PHP</span></div>
|
||||
<pre class="!m-0"><code class="language-php">flash()->error('Invalid email or password.');
|
||||
flash()->info('Forgot your password? Click here to reset.');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Form Validation --}}
|
||||
<div class="card">
|
||||
<div class="h-2 bg-gradient-to-r from-amber-500 to-yellow-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center space-x-3 mb-4">
|
||||
<div class="p-3 bg-amber-100 rounded-xl">
|
||||
<svg class="w-6 h-6 text-amber-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-lg font-bold text-gray-800">Form Validation</h3>
|
||||
<p class="text-sm text-gray-500">Multiple field errors</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 mb-4">Demonstrates displaying multiple validation errors from a form submission.</p>
|
||||
|
||||
<button onclick="runExample('validation')" class="btn btn-warning w-full mb-4">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"></path>
|
||||
</svg>
|
||||
Run Example
|
||||
</button>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header"><span>PHP</span></div>
|
||||
<pre class="!m-0"><code class="language-php">flash()->error('The email field is required.');
|
||||
flash()->error('Password must be at least 8 characters.');
|
||||
flash()->error('Please accept the terms and conditions.');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Shopping Cart --}}
|
||||
<div class="card">
|
||||
<div class="h-2 bg-gradient-to-r from-indigo-500 to-purple-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center space-x-3 mb-4">
|
||||
<div class="p-3 bg-indigo-100 rounded-xl">
|
||||
<svg class="w-6 h-6 text-indigo-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 3h2l.4 2M7 13h10l4-8H5.4M7 13L5.4 5M7 13l-2.293 2.293c-.63.63-.184 1.707.707 1.707H17m0 0a2 2 0 100 4 2 2 0 000-4zm-8 2a2 2 0 11-4 0 2 2 0 014 0z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-lg font-bold text-gray-800">Shopping Cart</h3>
|
||||
<p class="text-sm text-gray-500">E-commerce interactions</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 mb-4">Shows notifications for adding items to cart with stock warnings and promotions.</p>
|
||||
|
||||
<button onclick="runExample('shopping_cart')" class="btn btn-primary w-full mb-4">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"></path>
|
||||
</svg>
|
||||
Run Example
|
||||
</button>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header"><span>PHP</span></div>
|
||||
<pre class="!m-0"><code class="language-php">flash()->success('iPhone 15 Pro added to cart!');
|
||||
flash()->warning('Only 2 items left in stock!');
|
||||
flash()->info('Add $20 more for free shipping!');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- File Upload --}}
|
||||
<div class="card">
|
||||
<div class="h-2 bg-gradient-to-r from-sky-500 to-cyan-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center space-x-3 mb-4">
|
||||
<div class="p-3 bg-sky-100 rounded-xl">
|
||||
<svg class="w-6 h-6 text-sky-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-lg font-bold text-gray-800">File Upload</h3>
|
||||
<p class="text-sm text-gray-500">Upload progress and status</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 mb-4">Demonstrates file upload progress with success and additional info.</p>
|
||||
|
||||
<button onclick="runExample('file_upload')" class="btn btn-info w-full mb-4">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"></path>
|
||||
</svg>
|
||||
Run Example
|
||||
</button>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header"><span>PHP</span></div>
|
||||
<pre class="!m-0"><code class="language-php">flash()->success('document.pdf uploaded successfully!');
|
||||
flash()->info('File size: 2.4 MB');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Settings Saved --}}
|
||||
<div class="card">
|
||||
<div class="h-2 bg-gradient-to-r from-teal-500 to-green-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center space-x-3 mb-4">
|
||||
<div class="p-3 bg-teal-100 rounded-xl">
|
||||
<svg class="w-6 h-6 text-teal-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"></path>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-lg font-bold text-gray-800">Settings Saved</h3>
|
||||
<p class="text-sm text-gray-500">Preferences updated</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 mb-4">Shows settings save confirmation with additional context.</p>
|
||||
|
||||
<button onclick="runExample('settings')" class="btn btn-success w-full mb-4">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"></path>
|
||||
</svg>
|
||||
Run Example
|
||||
</button>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header"><span>PHP</span></div>
|
||||
<pre class="!m-0"><code class="language-php">flash()->success('Settings saved successfully!');
|
||||
flash()->info('Some changes may require a page refresh.');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Payment Success --}}
|
||||
<div class="card">
|
||||
<div class="h-2 bg-gradient-to-r from-green-500 to-emerald-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center space-x-3 mb-4">
|
||||
<div class="p-3 bg-green-100 rounded-xl">
|
||||
<svg class="w-6 h-6 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-lg font-bold text-gray-800">Payment Success</h3>
|
||||
<p class="text-sm text-gray-500">Transaction completed</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 mb-4">Payment confirmation with order details and receipt notification.</p>
|
||||
|
||||
<button onclick="runExample('payment_success')" class="btn btn-success w-full mb-4">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"></path>
|
||||
</svg>
|
||||
Run Example
|
||||
</button>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header"><span>PHP</span></div>
|
||||
<pre class="!m-0"><code class="language-php">flash()->success('Payment of $149.99 confirmed!');
|
||||
flash()->info('Order #12345 - Receipt sent to your email.');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Payment Failed --}}
|
||||
<div class="card">
|
||||
<div class="h-2 bg-gradient-to-r from-red-500 to-rose-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center space-x-3 mb-4">
|
||||
<div class="p-3 bg-red-100 rounded-xl">
|
||||
<svg class="w-6 h-6 text-red-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-lg font-bold text-gray-800">Payment Failed</h3>
|
||||
<p class="text-sm text-gray-500">Transaction declined</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 mb-4">Payment failure with helpful guidance for resolving the issue.</p>
|
||||
|
||||
<button onclick="runExample('payment_failed')" class="btn btn-danger w-full mb-4">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"></path>
|
||||
</svg>
|
||||
Run Example
|
||||
</button>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header"><span>PHP</span></div>
|
||||
<pre class="!m-0"><code class="language-php">flash()->error('Payment declined by your bank.');
|
||||
flash()->warning('Please try a different payment method.');
|
||||
flash()->info('Your cart has been saved.');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Delete Confirmation --}}
|
||||
<div class="card">
|
||||
<div class="h-2 bg-gradient-to-r from-pink-500 to-rose-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center space-x-3 mb-4">
|
||||
<div class="p-3 bg-pink-100 rounded-xl">
|
||||
<svg class="w-6 h-6 text-pink-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-lg font-bold text-gray-800">Delete Confirmation</h3>
|
||||
<p class="text-sm text-gray-500">SweetAlert dialog</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 mb-4">Uses SweetAlert for a confirmation dialog before deleting.</p>
|
||||
|
||||
<button onclick="runExample('delete_confirm')" class="btn btn-danger w-full mb-4">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"></path>
|
||||
</svg>
|
||||
Run Example
|
||||
</button>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header"><span>PHP</span></div>
|
||||
<pre class="!m-0"><code class="language-php">sweetalert()
|
||||
->showCancelButton()
|
||||
->confirmButtonText('Yes, delete it!')
|
||||
->cancelButtonText('Cancel')
|
||||
->warning('Are you sure? This cannot be undone.');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Session Expiring --}}
|
||||
<div class="card">
|
||||
<div class="h-2 bg-gradient-to-r from-orange-500 to-amber-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center space-x-3 mb-4">
|
||||
<div class="p-3 bg-orange-100 rounded-xl">
|
||||
<svg class="w-6 h-6 text-orange-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-lg font-bold text-gray-800">Session Expiring</h3>
|
||||
<p class="text-sm text-gray-500">Timeout warning</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 mb-4">Alerts user when their session is about to expire.</p>
|
||||
|
||||
<button onclick="runExample('session_expiring')" class="btn btn-warning w-full mb-4">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"></path>
|
||||
</svg>
|
||||
Run Example
|
||||
</button>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header"><span>PHP</span></div>
|
||||
<pre class="!m-0"><code class="language-php">flash()->warning('Your session will expire in 5 minutes.');
|
||||
flash()->info('Click anywhere to stay logged in.');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,197 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Home')
|
||||
|
||||
@section('content')
|
||||
{{-- Hero Section --}}
|
||||
<div class="text-center mb-12">
|
||||
<h1 class="text-4xl md:text-5xl font-bold text-gray-900 mb-4">
|
||||
Beautiful Flash Notifications
|
||||
</h1>
|
||||
<p class="text-xl text-gray-600 max-w-2xl mx-auto mb-8">
|
||||
PHPFlasher makes it easy to add elegant notifications to your Laravel application.
|
||||
Try the quick demos below!
|
||||
</p>
|
||||
|
||||
{{-- Quick Demo Buttons --}}
|
||||
<div class="flex flex-wrap justify-center gap-3 mb-8">
|
||||
<button onclick="showNotification({type: 'success', message: 'Operation completed successfully!', title: 'Success'})"
|
||||
class="btn btn-success">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
|
||||
</svg>
|
||||
Success
|
||||
</button>
|
||||
<button onclick="showNotification({type: 'error', message: 'Something went wrong. Please try again.', title: 'Error'})"
|
||||
class="btn btn-danger">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
|
||||
</svg>
|
||||
Error
|
||||
</button>
|
||||
<button onclick="showNotification({type: 'warning', message: 'Please review your input before continuing.', title: 'Warning'})"
|
||||
class="btn btn-warning">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"></path>
|
||||
</svg>
|
||||
Warning
|
||||
</button>
|
||||
<button onclick="showNotification({type: 'info', message: 'Here is some useful information for you.', title: 'Info'})"
|
||||
class="btn btn-info">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
Info
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Features Grid --}}
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 mb-12">
|
||||
{{-- Feature 1: Types --}}
|
||||
<a href="{{ route('types') }}" class="card group">
|
||||
<div class="h-2 bg-gradient-to-r from-emerald-500 to-teal-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center space-x-3 mb-3">
|
||||
<div class="p-2 bg-emerald-100 rounded-lg group-hover:bg-emerald-200 transition-colors">
|
||||
<svg class="w-6 h-6 text-emerald-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 8h10M7 12h4m1 8l-4-4H5a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v8a2 2 0 01-2 2h-3l-4 4z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="text-xl font-bold text-gray-800">Notification Types</h3>
|
||||
</div>
|
||||
<p class="text-gray-600">Success, error, warning, and info notifications for every use case.</p>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
{{-- Feature 2: Themes --}}
|
||||
<a href="{{ route('themes') }}" class="card group">
|
||||
<div class="h-2 bg-gradient-to-r from-purple-500 to-pink-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center space-x-3 mb-3">
|
||||
<div class="p-2 bg-purple-100 rounded-lg group-hover:bg-purple-200 transition-colors">
|
||||
<svg class="w-6 h-6 text-purple-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 21a4 4 0 01-4-4V5a2 2 0 012-2h4a2 2 0 012 2v12a4 4 0 01-4 4zm0 0h12a2 2 0 002-2v-4a2 2 0 00-2-2h-2.343M11 7.343l1.657-1.657a2 2 0 012.828 0l2.829 2.829a2 2 0 010 2.828l-8.486 8.485M7 17h.01"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="text-xl font-bold text-gray-800">17+ Themes</h3>
|
||||
</div>
|
||||
<p class="text-gray-600">Material, iOS, Slack, Amazon, and many more beautiful themes.</p>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
{{-- Feature 3: Adapters --}}
|
||||
<a href="{{ route('adapters') }}" class="card group">
|
||||
<div class="h-2 bg-gradient-to-r from-blue-500 to-cyan-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center space-x-3 mb-3">
|
||||
<div class="p-2 bg-blue-100 rounded-lg group-hover:bg-blue-200 transition-colors">
|
||||
<svg class="w-6 h-6 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 14v6m-3-3h6M6 10h2a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v2a2 2 0 002 2zm10 0h2a2 2 0 002-2V6a2 2 0 00-2-2h-2a2 2 0 00-2 2v2a2 2 0 002 2zM6 20h2a2 2 0 002-2v-2a2 2 0 00-2-2H6a2 2 0 00-2 2v2a2 2 0 002 2z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="text-xl font-bold text-gray-800">Multiple Adapters</h3>
|
||||
</div>
|
||||
<p class="text-gray-600">Toastr, SweetAlert, Noty, and Notyf adapters included.</p>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
{{-- Feature 4: Positions --}}
|
||||
<a href="{{ route('positions') }}" class="card group">
|
||||
<div class="h-2 bg-gradient-to-r from-amber-500 to-orange-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center space-x-3 mb-3">
|
||||
<div class="p-2 bg-amber-100 rounded-lg group-hover:bg-amber-200 transition-colors">
|
||||
<svg class="w-6 h-6 text-amber-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 5a1 1 0 011-1h14a1 1 0 011 1v2a1 1 0 01-1 1H5a1 1 0 01-1-1V5zM4 13a1 1 0 011-1h6a1 1 0 011 1v6a1 1 0 01-1 1H5a1 1 0 01-1-1v-6zM16 13a1 1 0 011-1h2a1 1 0 011 1v6a1 1 0 01-1 1h-2a1 1 0 01-1-1v-6z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="text-xl font-bold text-gray-800">Flexible Positions</h3>
|
||||
</div>
|
||||
<p class="text-gray-600">Place notifications anywhere on the screen.</p>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
{{-- Feature 5: Examples --}}
|
||||
<a href="{{ route('examples') }}" class="card group">
|
||||
<div class="h-2 bg-gradient-to-r from-rose-500 to-red-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center space-x-3 mb-3">
|
||||
<div class="p-2 bg-rose-100 rounded-lg group-hover:bg-rose-200 transition-colors">
|
||||
<svg class="w-6 h-6 text-rose-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="text-xl font-bold text-gray-800">Real Examples</h3>
|
||||
</div>
|
||||
<p class="text-gray-600">User registration, shopping cart, payments, and more.</p>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
{{-- Feature 6: Playground --}}
|
||||
<a href="{{ route('playground') }}" class="card group">
|
||||
<div class="h-2 bg-gradient-to-r from-indigo-500 to-violet-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center space-x-3 mb-3">
|
||||
<div class="p-2 bg-indigo-100 rounded-lg group-hover:bg-indigo-200 transition-colors">
|
||||
<svg class="w-6 h-6 text-indigo-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"></path>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="text-xl font-bold text-gray-800">Interactive Playground</h3>
|
||||
</div>
|
||||
<p class="text-gray-600">Build and customize notifications in real-time.</p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{{-- Quick Start Code --}}
|
||||
<div class="card mb-12">
|
||||
<div class="card-header">
|
||||
<h2 class="text-xl font-bold text-gray-800">Quick Start</h2>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p class="text-gray-600 mb-4">Get started with PHPFlasher in seconds. Just install and use!</p>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>Installation</span>
|
||||
</div>
|
||||
<pre class="!m-0"><code class="language-bash">composer require php-flasher/flasher-laravel</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>Usage</span>
|
||||
</div>
|
||||
<pre class="!m-0"><code class="language-php">// In your controller
|
||||
flash()->success('Profile updated successfully!');
|
||||
|
||||
// With options
|
||||
flash()->success('Welcome back!', [
|
||||
'position' => 'top-right',
|
||||
'timeout' => 5000,
|
||||
]);
|
||||
|
||||
// Using themes
|
||||
flash()->use('theme.material')->info('New feature available!');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- CTA Section --}}
|
||||
<div class="bg-gradient-to-r from-indigo-600 to-purple-600 rounded-2xl p-8 text-center text-white">
|
||||
<h2 class="text-2xl md:text-3xl font-bold mb-4">Ready to try PHPFlasher?</h2>
|
||||
<p class="text-indigo-100 mb-6 max-w-xl mx-auto">
|
||||
Explore the interactive playground to customize notifications and see the generated code.
|
||||
</p>
|
||||
<a href="{{ route('playground') }}" class="inline-flex items-center px-6 py-3 bg-white text-indigo-600 font-semibold rounded-lg hover:bg-indigo-50 transition-colors">
|
||||
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"></path>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
Open Playground
|
||||
</a>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,206 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||
<title>@yield('title', 'PHPFlasher Demo') - Laravel</title>
|
||||
|
||||
{{-- Tailwind CSS v4 CDN --}}
|
||||
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
|
||||
|
||||
{{-- Prism.js for syntax highlighting --}}
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-tomorrow.min.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/toolbar/prism-toolbar.min.css">
|
||||
|
||||
{{-- Custom Tailwind components --}}
|
||||
<script type="text/tailwindcss">
|
||||
@layer components {
|
||||
.btn {
|
||||
@apply px-4 py-2 rounded-lg font-medium transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-opacity-50 inline-flex items-center justify-center gap-2;
|
||||
}
|
||||
.btn-primary {
|
||||
@apply bg-indigo-600 text-white hover:bg-indigo-700 focus:ring-indigo-500;
|
||||
}
|
||||
.btn-success {
|
||||
@apply bg-emerald-600 text-white hover:bg-emerald-700 focus:ring-emerald-500;
|
||||
}
|
||||
.btn-danger {
|
||||
@apply bg-rose-600 text-white hover:bg-rose-700 focus:ring-rose-500;
|
||||
}
|
||||
.btn-warning {
|
||||
@apply bg-amber-500 text-white hover:bg-amber-600 focus:ring-amber-400;
|
||||
}
|
||||
.btn-info {
|
||||
@apply bg-sky-500 text-white hover:bg-sky-600 focus:ring-sky-400;
|
||||
}
|
||||
.btn-outline {
|
||||
@apply border border-gray-300 text-gray-700 bg-white hover:bg-gray-50 focus:ring-indigo-500;
|
||||
}
|
||||
.btn-sm {
|
||||
@apply px-3 py-1.5 text-sm;
|
||||
}
|
||||
.card {
|
||||
@apply bg-white rounded-xl shadow-md overflow-hidden hover:shadow-lg transition-shadow duration-300;
|
||||
}
|
||||
.card-header {
|
||||
@apply px-6 py-4 border-b border-gray-100;
|
||||
}
|
||||
.card-body {
|
||||
@apply p-6;
|
||||
}
|
||||
.code-block {
|
||||
@apply rounded-lg overflow-hidden shadow-lg my-4;
|
||||
}
|
||||
.code-header {
|
||||
@apply bg-gray-800 text-gray-300 px-4 py-2 flex justify-between items-center text-sm;
|
||||
}
|
||||
.section-title {
|
||||
@apply text-2xl font-bold text-gray-800 mb-2;
|
||||
}
|
||||
.section-subtitle {
|
||||
@apply text-gray-600 mb-6;
|
||||
}
|
||||
.nav-link {
|
||||
@apply px-3 py-2 rounded-lg text-gray-600 hover:text-indigo-600 hover:bg-indigo-50 transition-colors font-medium;
|
||||
}
|
||||
.nav-link-active {
|
||||
@apply text-indigo-600 bg-indigo-50;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@stack('styles')
|
||||
</head>
|
||||
<body class="bg-gray-50 antialiased text-gray-900 min-h-screen flex flex-col">
|
||||
{{-- Header --}}
|
||||
<header class="bg-white border-b border-gray-200 sticky top-0 z-50">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex justify-between items-center h-16">
|
||||
{{-- Logo --}}
|
||||
<a href="{{ route('home') }}" class="flex items-center space-x-2">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-8 w-8 text-indigo-600" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M13 10V3L4 14h7v7l9-11h-7z" />
|
||||
</svg>
|
||||
<span class="text-xl font-bold text-gray-900">PHPFlasher</span>
|
||||
<span class="hidden sm:inline-block px-2 py-0.5 text-xs font-medium bg-red-100 text-red-600 rounded-full">Laravel</span>
|
||||
</a>
|
||||
|
||||
{{-- Desktop Navigation --}}
|
||||
<nav class="hidden md:flex items-center space-x-1">
|
||||
<a href="{{ route('home') }}" class="nav-link @if(request()->routeIs('home')) nav-link-active @endif">Home</a>
|
||||
<a href="{{ route('types') }}" class="nav-link @if(request()->routeIs('types')) nav-link-active @endif">Types</a>
|
||||
<a href="{{ route('themes') }}" class="nav-link @if(request()->routeIs('themes')) nav-link-active @endif">Themes</a>
|
||||
<a href="{{ route('adapters') }}" class="nav-link @if(request()->routeIs('adapters')) nav-link-active @endif">Adapters</a>
|
||||
<a href="{{ route('positions') }}" class="nav-link @if(request()->routeIs('positions')) nav-link-active @endif">Positions</a>
|
||||
<a href="{{ route('examples') }}" class="nav-link @if(request()->routeIs('examples')) nav-link-active @endif">Examples</a>
|
||||
<a href="{{ route('playground') }}" class="nav-link @if(request()->routeIs('playground')) nav-link-active @endif">Playground</a>
|
||||
<a href="{{ route('livewire') }}" class="nav-link @if(request()->routeIs('livewire')) nav-link-active @endif">Livewire</a>
|
||||
</nav>
|
||||
|
||||
{{-- External Links --}}
|
||||
<div class="hidden md:flex items-center space-x-3">
|
||||
<a href="https://github.com/php-flasher/php-flasher" target="_blank" class="text-gray-500 hover:text-gray-700">
|
||||
<svg class="h-5 w-5" fill="currentColor" viewBox="0 0 24 24"><path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/></svg>
|
||||
</a>
|
||||
<a href="https://php-flasher.io" target="_blank" class="btn btn-primary btn-sm">
|
||||
Documentation
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{{-- Mobile menu button --}}
|
||||
<button id="mobile-menu-btn" class="md:hidden p-2 rounded-lg text-gray-500 hover:bg-gray-100">
|
||||
<svg class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Mobile Navigation --}}
|
||||
<div id="mobile-menu" class="hidden md:hidden border-t border-gray-200 bg-white">
|
||||
<div class="px-4 py-3 space-y-1">
|
||||
<a href="{{ route('home') }}" class="block px-3 py-2 rounded-lg @if(request()->routeIs('home')) bg-indigo-50 text-indigo-600 @else text-gray-600 hover:bg-gray-50 @endif">Home</a>
|
||||
<a href="{{ route('types') }}" class="block px-3 py-2 rounded-lg @if(request()->routeIs('types')) bg-indigo-50 text-indigo-600 @else text-gray-600 hover:bg-gray-50 @endif">Types</a>
|
||||
<a href="{{ route('themes') }}" class="block px-3 py-2 rounded-lg @if(request()->routeIs('themes')) bg-indigo-50 text-indigo-600 @else text-gray-600 hover:bg-gray-50 @endif">Themes</a>
|
||||
<a href="{{ route('adapters') }}" class="block px-3 py-2 rounded-lg @if(request()->routeIs('adapters')) bg-indigo-50 text-indigo-600 @else text-gray-600 hover:bg-gray-50 @endif">Adapters</a>
|
||||
<a href="{{ route('positions') }}" class="block px-3 py-2 rounded-lg @if(request()->routeIs('positions')) bg-indigo-50 text-indigo-600 @else text-gray-600 hover:bg-gray-50 @endif">Positions</a>
|
||||
<a href="{{ route('examples') }}" class="block px-3 py-2 rounded-lg @if(request()->routeIs('examples')) bg-indigo-50 text-indigo-600 @else text-gray-600 hover:bg-gray-50 @endif">Examples</a>
|
||||
<a href="{{ route('playground') }}" class="block px-3 py-2 rounded-lg @if(request()->routeIs('playground')) bg-indigo-50 text-indigo-600 @else text-gray-600 hover:bg-gray-50 @endif">Playground</a>
|
||||
<a href="{{ route('livewire') }}" class="block px-3 py-2 rounded-lg @if(request()->routeIs('livewire')) bg-indigo-50 text-indigo-600 @else text-gray-600 hover:bg-gray-50 @endif">Livewire</a>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{{-- Main Content --}}
|
||||
<main class="flex-1">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
||||
@yield('content')
|
||||
</div>
|
||||
</main>
|
||||
|
||||
{{-- Footer --}}
|
||||
<footer class="bg-white border-t border-gray-200 mt-auto">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6">
|
||||
<div class="flex flex-col md:flex-row justify-between items-center space-y-4 md:space-y-0">
|
||||
<div class="flex items-center space-x-2 text-gray-500">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M13 10V3L4 14h7v7l9-11h-7z" />
|
||||
</svg>
|
||||
<span>PHPFlasher Demo</span>
|
||||
</div>
|
||||
<div class="flex items-center space-x-6 text-sm text-gray-500">
|
||||
<a href="https://php-flasher.io" target="_blank" class="hover:text-indigo-600">Documentation</a>
|
||||
<a href="https://github.com/php-flasher/php-flasher" target="_blank" class="hover:text-indigo-600">GitHub</a>
|
||||
<span>Made with ❤️ by <a href="https://github.com/yoeunes" target="_blank" class="hover:text-indigo-600">Younes</a></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
{{-- Scripts --}}
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/prism.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-php.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/toolbar/prism-toolbar.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/copy-to-clipboard/prism-copy-to-clipboard.min.js"></script>
|
||||
|
||||
<script>
|
||||
// Mobile menu toggle
|
||||
document.getElementById('mobile-menu-btn')?.addEventListener('click', function() {
|
||||
document.getElementById('mobile-menu')?.classList.toggle('hidden');
|
||||
});
|
||||
|
||||
// CSRF token for AJAX requests
|
||||
window.csrfToken = '{{ csrf_token() }}';
|
||||
|
||||
// Helper function for notifications via AJAX
|
||||
window.showNotification = async function(options) {
|
||||
const response = await fetch('{{ route("notify") }}', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-TOKEN': window.csrfToken,
|
||||
'Accept': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(options),
|
||||
});
|
||||
return response.json();
|
||||
};
|
||||
|
||||
// Helper function for running examples
|
||||
window.runExample = async function(scenario) {
|
||||
const response = await fetch(`/example/${scenario}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-TOKEN': window.csrfToken,
|
||||
'Accept': 'application/json',
|
||||
},
|
||||
});
|
||||
return response.json();
|
||||
};
|
||||
</script>
|
||||
|
||||
@stack('scripts')
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,220 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Livewire Integration')
|
||||
|
||||
@section('content')
|
||||
<div class="mb-8">
|
||||
<h1 class="section-title">Livewire Integration</h1>
|
||||
<p class="section-subtitle">PHPFlasher works seamlessly with Laravel Livewire. See live examples below.</p>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-8">
|
||||
{{-- Counter Component --}}
|
||||
<div class="card">
|
||||
<div class="h-2 bg-gradient-to-r from-indigo-500 to-purple-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center space-x-3 mb-6">
|
||||
<div class="p-3 bg-indigo-100 rounded-xl">
|
||||
<svg class="w-6 h-6 text-indigo-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-lg font-bold text-gray-800">Counter Component</h3>
|
||||
<p class="text-sm text-gray-500">Simple state management</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@livewire('counter')
|
||||
|
||||
<div class="code-block mt-6">
|
||||
<div class="code-header">
|
||||
<span>app/Livewire/Counter.php</span>
|
||||
</div>
|
||||
<pre class="!m-0"><code class="language-php">class Counter extends Component
|
||||
{
|
||||
public int $count = 0;
|
||||
|
||||
public function increment(): void
|
||||
{
|
||||
$this->count++;
|
||||
flash()->success("Count increased to {$this->count}!");
|
||||
}
|
||||
|
||||
public function decrement(): void
|
||||
{
|
||||
$this->count--;
|
||||
flash()->warning("Count decreased to {$this->count}");
|
||||
}
|
||||
|
||||
public function reset(): void
|
||||
{
|
||||
$this->count = 0;
|
||||
flash()->info('Counter has been reset.');
|
||||
}
|
||||
}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Contact Form Component --}}
|
||||
<div class="card">
|
||||
<div class="h-2 bg-gradient-to-r from-emerald-500 to-teal-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center space-x-3 mb-6">
|
||||
<div class="p-3 bg-emerald-100 rounded-xl">
|
||||
<svg class="w-6 h-6 text-emerald-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-lg font-bold text-gray-800">Contact Form</h3>
|
||||
<p class="text-sm text-gray-500">Form validation example</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@livewire('contact-form')
|
||||
|
||||
<div class="code-block mt-6">
|
||||
<div class="code-header">
|
||||
<span>app/Livewire/ContactForm.php</span>
|
||||
</div>
|
||||
<pre class="!m-0"><code class="language-php">class ContactForm extends Component
|
||||
{
|
||||
public string $name = '';
|
||||
public string $email = '';
|
||||
public string $message = '';
|
||||
|
||||
protected $rules = [
|
||||
'name' => 'required|min:2',
|
||||
'email' => 'required|email',
|
||||
'message' => 'required|min:10',
|
||||
];
|
||||
|
||||
public function submit(): void
|
||||
{
|
||||
$this->validate();
|
||||
|
||||
// Process form...
|
||||
|
||||
flash()->success('Message sent successfully!');
|
||||
flash()->info('We will respond within 24 hours.');
|
||||
|
||||
$this->reset(['name', 'email', 'message']);
|
||||
}
|
||||
}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- SweetAlert Events --}}
|
||||
<div class="card mt-8">
|
||||
<div class="h-2 bg-gradient-to-r from-pink-500 to-rose-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center space-x-3 mb-6">
|
||||
<div class="p-3 bg-pink-100 rounded-xl">
|
||||
<svg class="w-6 h-6 text-pink-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-lg font-bold text-gray-800">SweetAlert Confirmations</h3>
|
||||
<p class="text-sm text-gray-500">Handle dialog responses in Livewire</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@livewire('delete-item')
|
||||
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6 mt-6">
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>Component</span>
|
||||
</div>
|
||||
<pre class="!m-0"><code class="language-php">class DeleteItem extends Component
|
||||
{
|
||||
protected $listeners = [
|
||||
'sweetalert:confirmed' => 'onConfirmed',
|
||||
'sweetalert:denied' => 'onDenied',
|
||||
];
|
||||
|
||||
public function confirmDelete(): void
|
||||
{
|
||||
sweetalert()
|
||||
->showDenyButton()
|
||||
->showCancelButton()
|
||||
->confirmButtonText('Yes, delete!')
|
||||
->denyButtonText('Keep it')
|
||||
->warning('Delete this item?');
|
||||
}
|
||||
|
||||
public function onConfirmed(array $payload): void
|
||||
{
|
||||
// Delete the item...
|
||||
flash()->success('Item deleted!');
|
||||
}
|
||||
|
||||
public function onDenied(array $payload): void
|
||||
{
|
||||
flash()->info('Item was kept.');
|
||||
}
|
||||
}</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>Blade Template</span>
|
||||
</div>
|
||||
<pre class="!m-0"><code class="language-php"><div>
|
||||
<button wire:click="confirmDelete"
|
||||
class="btn btn-danger">
|
||||
Delete Item
|
||||
</button>
|
||||
</div></code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Installation Guide --}}
|
||||
<div class="card mt-8">
|
||||
<div class="card-header">
|
||||
<h2 class="text-xl font-bold text-gray-800">Livewire Setup</h2>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||
<div>
|
||||
<h3 class="font-semibold text-gray-800 mb-3">1. Install PHPFlasher</h3>
|
||||
<div class="code-block">
|
||||
<div class="code-header"><span>Terminal</span></div>
|
||||
<pre class="!m-0"><code class="language-bash">composer require php-flasher/flasher-laravel</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3 class="font-semibold text-gray-800 mb-3">2. Use in Components</h3>
|
||||
<div class="code-block">
|
||||
<div class="code-header"><span>PHP</span></div>
|
||||
<pre class="!m-0"><code class="language-php">public function save()
|
||||
{
|
||||
// Your logic...
|
||||
flash()->success('Saved!');
|
||||
}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-6 p-4 bg-indigo-50 rounded-lg">
|
||||
<div class="flex items-start space-x-3">
|
||||
<svg class="w-6 h-6 text-indigo-600 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
<div>
|
||||
<h4 class="font-semibold text-indigo-800">Automatic Livewire Support</h4>
|
||||
<p class="text-indigo-700 text-sm mt-1">PHPFlasher automatically detects Livewire requests and handles them appropriately. No additional configuration needed!</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,41 @@
|
||||
<form wire:submit="submit" class="space-y-4">
|
||||
<div>
|
||||
<label for="name" class="block text-sm font-medium text-gray-700 mb-1">Name</label>
|
||||
<input type="text" id="name" wire:model="name"
|
||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-emerald-500 focus:border-emerald-500 @error('name') border-rose-500 @enderror"
|
||||
placeholder="Your name">
|
||||
@error('name')
|
||||
<p class="mt-1 text-sm text-rose-500">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="email" class="block text-sm font-medium text-gray-700 mb-1">Email</label>
|
||||
<input type="email" id="email" wire:model="email"
|
||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-emerald-500 focus:border-emerald-500 @error('email') border-rose-500 @enderror"
|
||||
placeholder="your@email.com">
|
||||
@error('email')
|
||||
<p class="mt-1 text-sm text-rose-500">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="message" class="block text-sm font-medium text-gray-700 mb-1">Message</label>
|
||||
<textarea id="message" wire:model="message" rows="3"
|
||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-emerald-500 focus:border-emerald-500 @error('message') border-rose-500 @enderror"
|
||||
placeholder="Your message..."></textarea>
|
||||
@error('message')
|
||||
<p class="mt-1 text-sm text-rose-500">{{ $message }}</p>
|
||||
@enderror
|
||||
</div>
|
||||
|
||||
<button type="submit"
|
||||
class="w-full px-4 py-2 bg-emerald-600 hover:bg-emerald-700 text-white font-medium rounded-lg transition-colors flex items-center justify-center space-x-2">
|
||||
<svg wire:loading wire:target="submit" class="animate-spin h-5 w-5" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
||||
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
||||
</svg>
|
||||
<span wire:loading.remove wire:target="submit">Send Message</span>
|
||||
<span wire:loading wire:target="submit">Sending...</span>
|
||||
</button>
|
||||
</form>
|
||||
@@ -1,7 +1,22 @@
|
||||
<div>
|
||||
<h1>{{ $count }}</h1>
|
||||
<div class="flex items-center justify-center space-x-4">
|
||||
<button wire:click="decrement"
|
||||
class="w-12 h-12 bg-rose-500 hover:bg-rose-600 text-white rounded-full flex items-center justify-center text-2xl font-bold transition-colors">
|
||||
-
|
||||
</button>
|
||||
|
||||
<button wire:click="increment">+</button>
|
||||
<div class="w-24 h-24 bg-gradient-to-br from-indigo-500 to-purple-600 rounded-2xl flex items-center justify-center">
|
||||
<span class="text-4xl font-bold text-white">{{ $count }}</span>
|
||||
</div>
|
||||
|
||||
<button wire:click="decrement">-</button>
|
||||
<button wire:click="increment"
|
||||
class="w-12 h-12 bg-emerald-500 hover:bg-emerald-600 text-white rounded-full flex items-center justify-center text-2xl font-bold transition-colors">
|
||||
+
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-center mt-4">
|
||||
<button wire:click="reset"
|
||||
class="px-4 py-2 bg-gray-200 hover:bg-gray-300 text-gray-700 rounded-lg text-sm font-medium transition-colors">
|
||||
Reset
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
<div class="flex flex-col items-center space-y-4">
|
||||
<div class="flex items-center space-x-4">
|
||||
<div class="w-16 h-16 bg-gray-100 rounded-lg flex items-center justify-center">
|
||||
<svg class="w-8 h-8 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h4 class="font-semibold text-gray-800">Important Document.pdf</h4>
|
||||
<p class="text-sm text-gray-500">2.4 MB - Modified today</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button wire:click="confirmDelete"
|
||||
class="px-6 py-2 bg-rose-600 hover:bg-rose-700 text-white font-medium rounded-lg transition-colors flex items-center space-x-2">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"></path>
|
||||
</svg>
|
||||
<span>Delete File</span>
|
||||
</button>
|
||||
</div>
|
||||
@@ -0,0 +1,390 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Playground')
|
||||
|
||||
@section('content')
|
||||
<div class="mb-8">
|
||||
<h1 class="section-title">Interactive Playground</h1>
|
||||
<p class="section-subtitle">Build and customize notifications in real-time. See the generated PHP code instantly.</p>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-8">
|
||||
{{-- Configuration Panel --}}
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h2 class="text-xl font-bold text-gray-800">Configuration</h2>
|
||||
</div>
|
||||
<div class="card-body space-y-6">
|
||||
{{-- Type --}}
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">Notification Type</label>
|
||||
<div class="grid grid-cols-4 gap-2">
|
||||
<button onclick="setType('success')" id="type-success" class="type-btn px-3 py-2 rounded-lg border-2 border-emerald-500 bg-emerald-50 text-emerald-700 font-medium text-sm">
|
||||
Success
|
||||
</button>
|
||||
<button onclick="setType('error')" id="type-error" class="type-btn px-3 py-2 rounded-lg border-2 border-gray-200 bg-white text-gray-600 font-medium text-sm hover:border-rose-500 hover:bg-rose-50 hover:text-rose-700">
|
||||
Error
|
||||
</button>
|
||||
<button onclick="setType('warning')" id="type-warning" class="type-btn px-3 py-2 rounded-lg border-2 border-gray-200 bg-white text-gray-600 font-medium text-sm hover:border-amber-500 hover:bg-amber-50 hover:text-amber-700">
|
||||
Warning
|
||||
</button>
|
||||
<button onclick="setType('info')" id="type-info" class="type-btn px-3 py-2 rounded-lg border-2 border-gray-200 bg-white text-gray-600 font-medium text-sm hover:border-sky-500 hover:bg-sky-50 hover:text-sky-700">
|
||||
Info
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Title --}}
|
||||
<div>
|
||||
<label for="title" class="block text-sm font-medium text-gray-700 mb-2">Title (optional)</label>
|
||||
<input type="text" id="title" placeholder="Enter a title..."
|
||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"
|
||||
oninput="updateCode()">
|
||||
</div>
|
||||
|
||||
{{-- Message --}}
|
||||
<div>
|
||||
<label for="message" class="block text-sm font-medium text-gray-700 mb-2">Message</label>
|
||||
<textarea id="message" rows="2" placeholder="Enter your notification message..."
|
||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"
|
||||
oninput="updateCode()">Operation completed successfully!</textarea>
|
||||
</div>
|
||||
|
||||
{{-- Position --}}
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">Position</label>
|
||||
<select id="position" onchange="updateCode()"
|
||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500">
|
||||
<option value="top-right" selected>Top Right (default)</option>
|
||||
<option value="top-left">Top Left</option>
|
||||
<option value="top-center">Top Center</option>
|
||||
<option value="bottom-right">Bottom Right</option>
|
||||
<option value="bottom-left">Bottom Left</option>
|
||||
<option value="bottom-center">Bottom Center</option>
|
||||
<option value="center">Center</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
{{-- Theme --}}
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">Theme</label>
|
||||
<select id="theme" onchange="updateCode()"
|
||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500">
|
||||
<option value="">Default (Flasher)</option>
|
||||
<option value="flasher">Flasher</option>
|
||||
<option value="material">Material</option>
|
||||
<option value="ios">iOS</option>
|
||||
<option value="slack">Slack</option>
|
||||
<option value="amazon">Amazon</option>
|
||||
<option value="google">Google</option>
|
||||
<option value="facebook">Facebook</option>
|
||||
<option value="minimal">Minimal</option>
|
||||
<option value="neon">Neon</option>
|
||||
<option value="emerald">Emerald</option>
|
||||
<option value="sapphire">Sapphire</option>
|
||||
<option value="ruby">Ruby</option>
|
||||
<option value="amber">Amber</option>
|
||||
<option value="jade">Jade</option>
|
||||
<option value="onyx">Onyx</option>
|
||||
<option value="crystal">Crystal</option>
|
||||
<option value="aurora">Aurora</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
{{-- Adapter --}}
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">Adapter</label>
|
||||
<select id="adapter" onchange="updateCode()"
|
||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500">
|
||||
<option value="flasher" selected>Flasher (default)</option>
|
||||
<option value="toastr">Toastr</option>
|
||||
<option value="sweetalert">SweetAlert</option>
|
||||
<option value="noty">Noty</option>
|
||||
<option value="notyf">Notyf</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
{{-- Timeout --}}
|
||||
<div>
|
||||
<label for="timeout" class="block text-sm font-medium text-gray-700 mb-2">
|
||||
Timeout: <span id="timeout-value">5000</span>ms
|
||||
</label>
|
||||
<input type="range" id="timeout" min="1000" max="10000" step="500" value="5000"
|
||||
class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer"
|
||||
oninput="document.getElementById('timeout-value').textContent = this.value; updateCode()">
|
||||
</div>
|
||||
|
||||
{{-- Show Button --}}
|
||||
<button onclick="showPlaygroundNotification()" class="btn btn-primary w-full">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"></path>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
Show Notification
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Code Preview --}}
|
||||
<div class="space-y-6">
|
||||
<div class="card">
|
||||
<div class="card-header flex justify-between items-center">
|
||||
<h2 class="text-xl font-bold text-gray-800">Generated Code</h2>
|
||||
<button onclick="copyCode()" class="btn btn-sm btn-outline">
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"></path>
|
||||
</svg>
|
||||
Copy
|
||||
</button>
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
<div class="code-block !my-0 !rounded-none">
|
||||
<div class="code-header">
|
||||
<span>PHP</span>
|
||||
</div>
|
||||
<pre class="!m-0"><code class="language-php" id="generated-code">flash()->success('Operation completed successfully!');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Preview Card --}}
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h2 class="text-xl font-bold text-gray-800">Preview</h2>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="bg-gray-100 rounded-lg p-6 min-h-[200px] flex items-center justify-center">
|
||||
<div id="preview-notification" class="max-w-sm w-full">
|
||||
{{-- Preview will be rendered here --}}
|
||||
<div class="bg-emerald-500 text-white p-4 rounded-lg shadow-lg">
|
||||
<div class="flex items-start space-x-3">
|
||||
<svg class="w-6 h-6 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
<div>
|
||||
<p id="preview-title" class="font-semibold hidden"></p>
|
||||
<p id="preview-message" class="text-sm opacity-90">Operation completed successfully!</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-sm text-gray-500 mt-3 text-center">This is a static preview. Click "Show Notification" to see the real notification.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Quick Examples --}}
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h2 class="text-xl font-bold text-gray-800">Quick Examples</h2>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="space-y-2">
|
||||
<button onclick="loadExample('simple')" class="btn btn-outline w-full justify-start">
|
||||
Simple Notification
|
||||
</button>
|
||||
<button onclick="loadExample('with_title')" class="btn btn-outline w-full justify-start">
|
||||
With Title
|
||||
</button>
|
||||
<button onclick="loadExample('material_theme')" class="btn btn-outline w-full justify-start">
|
||||
Material Theme
|
||||
</button>
|
||||
<button onclick="loadExample('toastr_adapter')" class="btn btn-outline w-full justify-start">
|
||||
Toastr Adapter
|
||||
</button>
|
||||
<button onclick="loadExample('bottom_center')" class="btn btn-outline w-full justify-start">
|
||||
Bottom Center Position
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
let currentType = 'success';
|
||||
const typeColors = {
|
||||
success: { border: 'border-emerald-500', bg: 'bg-emerald-50', text: 'text-emerald-700', preview: 'bg-emerald-500' },
|
||||
error: { border: 'border-rose-500', bg: 'bg-rose-50', text: 'text-rose-700', preview: 'bg-rose-500' },
|
||||
warning: { border: 'border-amber-500', bg: 'bg-amber-50', text: 'text-amber-700', preview: 'bg-amber-500' },
|
||||
info: { border: 'border-sky-500', bg: 'bg-sky-50', text: 'text-sky-700', preview: 'bg-sky-500' }
|
||||
};
|
||||
|
||||
function setType(type) {
|
||||
currentType = type;
|
||||
|
||||
// Update button styles
|
||||
document.querySelectorAll('.type-btn').forEach(btn => {
|
||||
btn.className = 'type-btn px-3 py-2 rounded-lg border-2 border-gray-200 bg-white text-gray-600 font-medium text-sm';
|
||||
});
|
||||
|
||||
const activeBtn = document.getElementById(`type-${type}`);
|
||||
const colors = typeColors[type];
|
||||
activeBtn.className = `type-btn px-3 py-2 rounded-lg border-2 ${colors.border} ${colors.bg} ${colors.text} font-medium text-sm`;
|
||||
|
||||
// Update preview
|
||||
updatePreview();
|
||||
updateCode();
|
||||
}
|
||||
|
||||
function updatePreview() {
|
||||
const previewDiv = document.querySelector('#preview-notification > div');
|
||||
const colors = typeColors[currentType];
|
||||
previewDiv.className = `${colors.preview} text-white p-4 rounded-lg shadow-lg`;
|
||||
|
||||
const title = document.getElementById('title').value;
|
||||
const message = document.getElementById('message').value;
|
||||
|
||||
document.getElementById('preview-title').textContent = title;
|
||||
document.getElementById('preview-title').classList.toggle('hidden', !title);
|
||||
document.getElementById('preview-message').textContent = message || 'Your notification message...';
|
||||
}
|
||||
|
||||
function updateCode() {
|
||||
const type = currentType;
|
||||
const title = document.getElementById('title').value;
|
||||
const message = document.getElementById('message').value || 'Your message here';
|
||||
const position = document.getElementById('position').value;
|
||||
const theme = document.getElementById('theme').value;
|
||||
const adapter = document.getElementById('adapter').value;
|
||||
const timeout = document.getElementById('timeout').value;
|
||||
|
||||
let code = '';
|
||||
const hasOptions = position !== 'top-right' || timeout !== '5000';
|
||||
|
||||
// Build the code
|
||||
if (theme) {
|
||||
code = `flash()->use('theme.${theme}')`;
|
||||
} else if (adapter !== 'flasher') {
|
||||
code = `${adapter}()`;
|
||||
} else {
|
||||
code = 'flash()';
|
||||
}
|
||||
|
||||
// Add options if needed
|
||||
if (hasOptions) {
|
||||
const options = [];
|
||||
if (position !== 'top-right') {
|
||||
options.push(`'position' => '${position}'`);
|
||||
}
|
||||
if (timeout !== '5000') {
|
||||
options.push(`'timeout' => ${timeout}`);
|
||||
}
|
||||
|
||||
if (title) {
|
||||
code += `\n ->${type}('${message}', '${title}', [${options.join(', ')}]);`;
|
||||
} else {
|
||||
code += `\n ->${type}('${message}', [${options.join(', ')}]);`;
|
||||
}
|
||||
} else {
|
||||
if (title) {
|
||||
code += `->${type}('${message}', '${title}');`;
|
||||
} else {
|
||||
code += `->${type}('${message}');`;
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById('generated-code').textContent = code;
|
||||
Prism.highlightElement(document.getElementById('generated-code'));
|
||||
|
||||
updatePreview();
|
||||
}
|
||||
|
||||
function showPlaygroundNotification() {
|
||||
const options = {
|
||||
type: currentType,
|
||||
message: document.getElementById('message').value || 'Your message here',
|
||||
title: document.getElementById('title').value || undefined,
|
||||
position: document.getElementById('position').value,
|
||||
theme: document.getElementById('theme').value || undefined,
|
||||
adapter: document.getElementById('adapter').value,
|
||||
timeout: parseInt(document.getElementById('timeout').value)
|
||||
};
|
||||
|
||||
showNotification(options);
|
||||
}
|
||||
|
||||
function copyCode() {
|
||||
const code = document.getElementById('generated-code').textContent;
|
||||
navigator.clipboard.writeText(code).then(() => {
|
||||
// Show success feedback
|
||||
const btn = event.target.closest('button');
|
||||
const originalText = btn.innerHTML;
|
||||
btn.innerHTML = '<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg> Copied!';
|
||||
setTimeout(() => {
|
||||
btn.innerHTML = originalText;
|
||||
}, 2000);
|
||||
});
|
||||
}
|
||||
|
||||
function loadExample(example) {
|
||||
const examples = {
|
||||
simple: {
|
||||
type: 'success',
|
||||
title: '',
|
||||
message: 'Data saved successfully!',
|
||||
position: 'top-right',
|
||||
theme: '',
|
||||
adapter: 'flasher',
|
||||
timeout: 5000
|
||||
},
|
||||
with_title: {
|
||||
type: 'info',
|
||||
title: 'New Update',
|
||||
message: 'Version 2.0 is now available!',
|
||||
position: 'top-right',
|
||||
theme: '',
|
||||
adapter: 'flasher',
|
||||
timeout: 5000
|
||||
},
|
||||
material_theme: {
|
||||
type: 'success',
|
||||
title: '',
|
||||
message: 'Material design notification!',
|
||||
position: 'top-right',
|
||||
theme: 'material',
|
||||
adapter: 'flasher',
|
||||
timeout: 5000
|
||||
},
|
||||
toastr_adapter: {
|
||||
type: 'warning',
|
||||
title: 'Warning',
|
||||
message: 'Please review your changes',
|
||||
position: 'top-right',
|
||||
theme: '',
|
||||
adapter: 'toastr',
|
||||
timeout: 5000
|
||||
},
|
||||
bottom_center: {
|
||||
type: 'error',
|
||||
title: '',
|
||||
message: 'Something went wrong!',
|
||||
position: 'bottom-center',
|
||||
theme: '',
|
||||
adapter: 'flasher',
|
||||
timeout: 5000
|
||||
}
|
||||
};
|
||||
|
||||
const ex = examples[example];
|
||||
if (ex) {
|
||||
setType(ex.type);
|
||||
document.getElementById('title').value = ex.title;
|
||||
document.getElementById('message').value = ex.message;
|
||||
document.getElementById('position').value = ex.position;
|
||||
document.getElementById('theme').value = ex.theme;
|
||||
document.getElementById('adapter').value = ex.adapter;
|
||||
document.getElementById('timeout').value = ex.timeout;
|
||||
document.getElementById('timeout-value').textContent = ex.timeout;
|
||||
updateCode();
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
updateCode();
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
@@ -0,0 +1,211 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Positions')
|
||||
|
||||
@section('content')
|
||||
<div class="mb-8">
|
||||
<h1 class="section-title">Notification Positions</h1>
|
||||
<p class="section-subtitle">Place your notifications anywhere on the screen. Click any position to see it in action.</p>
|
||||
</div>
|
||||
|
||||
{{-- Interactive Position Grid --}}
|
||||
<div class="card mb-8">
|
||||
<div class="card-header">
|
||||
<h2 class="text-xl font-bold text-gray-800">Click a Position</h2>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="bg-gray-100 rounded-xl p-4 relative" style="min-height: 400px;">
|
||||
{{-- Visual Browser Frame --}}
|
||||
<div class="bg-white rounded-lg shadow-lg overflow-hidden h-full" style="min-height: 380px;">
|
||||
{{-- Browser Header --}}
|
||||
<div class="bg-gray-200 px-4 py-2 flex items-center space-x-2">
|
||||
<div class="w-3 h-3 bg-red-400 rounded-full"></div>
|
||||
<div class="w-3 h-3 bg-yellow-400 rounded-full"></div>
|
||||
<div class="w-3 h-3 bg-green-400 rounded-full"></div>
|
||||
<div class="flex-1 ml-4">
|
||||
<div class="bg-white rounded px-3 py-1 text-sm text-gray-500 max-w-md">your-app.com</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Position Grid --}}
|
||||
<div class="grid grid-cols-3 grid-rows-3 gap-2 p-4" style="min-height: 340px;">
|
||||
{{-- Top Left --}}
|
||||
<button onclick="showNotification({type: 'info', message: 'Top Left notification', position: 'top-left'})"
|
||||
class="flex items-start justify-start p-4 bg-indigo-50 hover:bg-indigo-100 rounded-lg transition-colors group">
|
||||
<div class="bg-indigo-500 text-white px-3 py-2 rounded-lg text-sm font-medium group-hover:scale-105 transition-transform">
|
||||
top-left
|
||||
</div>
|
||||
</button>
|
||||
|
||||
{{-- Top Center --}}
|
||||
<button onclick="showNotification({type: 'info', message: 'Top Center notification', position: 'top-center'})"
|
||||
class="flex items-start justify-center p-4 bg-purple-50 hover:bg-purple-100 rounded-lg transition-colors group">
|
||||
<div class="bg-purple-500 text-white px-3 py-2 rounded-lg text-sm font-medium group-hover:scale-105 transition-transform">
|
||||
top-center
|
||||
</div>
|
||||
</button>
|
||||
|
||||
{{-- Top Right --}}
|
||||
<button onclick="showNotification({type: 'info', message: 'Top Right notification', position: 'top-right'})"
|
||||
class="flex items-start justify-end p-4 bg-pink-50 hover:bg-pink-100 rounded-lg transition-colors group">
|
||||
<div class="bg-pink-500 text-white px-3 py-2 rounded-lg text-sm font-medium group-hover:scale-105 transition-transform">
|
||||
top-right
|
||||
</div>
|
||||
</button>
|
||||
|
||||
{{-- Center Left --}}
|
||||
<button onclick="showNotification({type: 'info', message: 'Center Left notification', position: 'center-left'})"
|
||||
class="flex items-center justify-start p-4 bg-sky-50 hover:bg-sky-100 rounded-lg transition-colors group">
|
||||
<div class="bg-sky-500 text-white px-3 py-2 rounded-lg text-sm font-medium group-hover:scale-105 transition-transform">
|
||||
center-left
|
||||
</div>
|
||||
</button>
|
||||
|
||||
{{-- Center --}}
|
||||
<button onclick="showNotification({type: 'info', message: 'Center notification', position: 'center'})"
|
||||
class="flex items-center justify-center p-4 bg-amber-50 hover:bg-amber-100 rounded-lg transition-colors group">
|
||||
<div class="bg-amber-500 text-white px-3 py-2 rounded-lg text-sm font-medium group-hover:scale-105 transition-transform">
|
||||
center
|
||||
</div>
|
||||
</button>
|
||||
|
||||
{{-- Center Right --}}
|
||||
<button onclick="showNotification({type: 'info', message: 'Center Right notification', position: 'center-right'})"
|
||||
class="flex items-center justify-end p-4 bg-emerald-50 hover:bg-emerald-100 rounded-lg transition-colors group">
|
||||
<div class="bg-emerald-500 text-white px-3 py-2 rounded-lg text-sm font-medium group-hover:scale-105 transition-transform">
|
||||
center-right
|
||||
</div>
|
||||
</button>
|
||||
|
||||
{{-- Bottom Left --}}
|
||||
<button onclick="showNotification({type: 'info', message: 'Bottom Left notification', position: 'bottom-left'})"
|
||||
class="flex items-end justify-start p-4 bg-rose-50 hover:bg-rose-100 rounded-lg transition-colors group">
|
||||
<div class="bg-rose-500 text-white px-3 py-2 rounded-lg text-sm font-medium group-hover:scale-105 transition-transform">
|
||||
bottom-left
|
||||
</div>
|
||||
</button>
|
||||
|
||||
{{-- Bottom Center --}}
|
||||
<button onclick="showNotification({type: 'info', message: 'Bottom Center notification', position: 'bottom-center'})"
|
||||
class="flex items-end justify-center p-4 bg-teal-50 hover:bg-teal-100 rounded-lg transition-colors group">
|
||||
<div class="bg-teal-500 text-white px-3 py-2 rounded-lg text-sm font-medium group-hover:scale-105 transition-transform">
|
||||
bottom-center
|
||||
</div>
|
||||
</button>
|
||||
|
||||
{{-- Bottom Right --}}
|
||||
<button onclick="showNotification({type: 'info', message: 'Bottom Right notification', position: 'bottom-right'})"
|
||||
class="flex items-end justify-end p-4 bg-orange-50 hover:bg-orange-100 rounded-lg transition-colors group">
|
||||
<div class="bg-orange-500 text-white px-3 py-2 rounded-lg text-sm font-medium group-hover:scale-105 transition-transform">
|
||||
bottom-right
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Quick Buttons --}}
|
||||
<div class="card mb-8">
|
||||
<div class="card-header">
|
||||
<h2 class="text-xl font-bold text-gray-800">Quick Position Tests</h2>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="flex flex-wrap gap-3">
|
||||
<button onclick="showNotification({type: 'success', message: 'Top Right (Default)', position: 'top-right'})"
|
||||
class="btn btn-success">Top Right</button>
|
||||
<button onclick="showNotification({type: 'error', message: 'Top Left notification', position: 'top-left'})"
|
||||
class="btn btn-danger">Top Left</button>
|
||||
<button onclick="showNotification({type: 'warning', message: 'Bottom Right notification', position: 'bottom-right'})"
|
||||
class="btn btn-warning">Bottom Right</button>
|
||||
<button onclick="showNotification({type: 'info', message: 'Bottom Left notification', position: 'bottom-left'})"
|
||||
class="btn btn-info">Bottom Left</button>
|
||||
<button onclick="showNotification({type: 'success', message: 'Top Center notification', position: 'top-center'})"
|
||||
class="btn btn-outline">Top Center</button>
|
||||
<button onclick="showNotification({type: 'info', message: 'Bottom Center notification', position: 'bottom-center'})"
|
||||
class="btn btn-outline">Bottom Center</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Code Examples --}}
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="text-lg font-bold text-gray-800">Inline Position</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p class="text-gray-600 mb-4">Set the position directly when creating a notification.</p>
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>PHP</span>
|
||||
</div>
|
||||
<pre class="!m-0"><code class="language-php">flash()
|
||||
->option('position', 'top-left')
|
||||
->success('Profile updated!');
|
||||
|
||||
// Or use the fluent method
|
||||
flash()
|
||||
->position('bottom-right')
|
||||
->info('New message received!');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="text-lg font-bold text-gray-800">Global Configuration</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p class="text-gray-600 mb-4">Set a default position for all notifications in your config file.</p>
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>config/flasher.php</span>
|
||||
</div>
|
||||
<pre class="!m-0"><code class="language-php">return [
|
||||
'default' => 'flasher',
|
||||
'options' => [
|
||||
'position' => 'bottom-right',
|
||||
],
|
||||
];</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Position Reference --}}
|
||||
<div class="card mt-6">
|
||||
<div class="card-header">
|
||||
<h2 class="text-xl font-bold text-gray-800">Available Positions</h2>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
<div class="p-4 bg-gray-50 rounded-lg">
|
||||
<h4 class="font-semibold text-gray-800 mb-2">Top Positions</h4>
|
||||
<ul class="space-y-1 text-gray-600 text-sm">
|
||||
<li><code class="bg-gray-200 px-2 py-0.5 rounded">top-left</code></li>
|
||||
<li><code class="bg-gray-200 px-2 py-0.5 rounded">top-center</code></li>
|
||||
<li><code class="bg-gray-200 px-2 py-0.5 rounded">top-right</code> <span class="text-emerald-600">(default)</span></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="p-4 bg-gray-50 rounded-lg">
|
||||
<h4 class="font-semibold text-gray-800 mb-2">Center Positions</h4>
|
||||
<ul class="space-y-1 text-gray-600 text-sm">
|
||||
<li><code class="bg-gray-200 px-2 py-0.5 rounded">center-left</code></li>
|
||||
<li><code class="bg-gray-200 px-2 py-0.5 rounded">center</code></li>
|
||||
<li><code class="bg-gray-200 px-2 py-0.5 rounded">center-right</code></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="p-4 bg-gray-50 rounded-lg">
|
||||
<h4 class="font-semibold text-gray-800 mb-2">Bottom Positions</h4>
|
||||
<ul class="space-y-1 text-gray-600 text-sm">
|
||||
<li><code class="bg-gray-200 px-2 py-0.5 rounded">bottom-left</code></li>
|
||||
<li><code class="bg-gray-200 px-2 py-0.5 rounded">bottom-center</code></li>
|
||||
<li><code class="bg-gray-200 px-2 py-0.5 rounded">bottom-right</code></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,75 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Themes')
|
||||
|
||||
@section('content')
|
||||
<div class="mb-8">
|
||||
<h1 class="section-title">Theme Gallery</h1>
|
||||
<p class="section-subtitle">Choose from 17+ beautiful themes to match your application's design.</p>
|
||||
</div>
|
||||
|
||||
{{-- Theme Grid --}}
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4 mb-12">
|
||||
@php
|
||||
$themes = [
|
||||
['name' => 'flasher', 'label' => 'Flasher', 'desc' => 'Default theme', 'gradient' => 'from-indigo-500 to-indigo-600'],
|
||||
['name' => 'material', 'label' => 'Material', 'desc' => 'Google Material', 'gradient' => 'from-blue-500 to-blue-600'],
|
||||
['name' => 'ios', 'label' => 'iOS', 'desc' => 'Apple style', 'gradient' => 'from-slate-600 to-slate-700'],
|
||||
['name' => 'slack', 'label' => 'Slack', 'desc' => 'Slack messaging', 'gradient' => 'from-purple-500 to-purple-600'],
|
||||
['name' => 'amazon', 'label' => 'Amazon', 'desc' => 'Amazon alerts', 'gradient' => 'from-orange-500 to-orange-600'],
|
||||
['name' => 'google', 'label' => 'Google', 'desc' => 'Google notifications', 'gradient' => 'from-red-500 to-yellow-500'],
|
||||
['name' => 'facebook', 'label' => 'Facebook', 'desc' => 'Facebook style', 'gradient' => 'from-blue-600 to-blue-700'],
|
||||
['name' => 'minimal', 'label' => 'Minimal', 'desc' => 'Ultra clean', 'gradient' => 'from-gray-400 to-gray-500'],
|
||||
['name' => 'neon', 'label' => 'Neon', 'desc' => 'Bright & bold', 'gradient' => 'from-pink-500 to-rose-500'],
|
||||
['name' => 'emerald', 'label' => 'Emerald', 'desc' => 'Green palette', 'gradient' => 'from-emerald-500 to-green-600'],
|
||||
['name' => 'sapphire', 'label' => 'Sapphire', 'desc' => 'Blue elegance', 'gradient' => 'from-blue-500 to-indigo-600'],
|
||||
['name' => 'ruby', 'label' => 'Ruby', 'desc' => 'Red accents', 'gradient' => 'from-red-500 to-rose-600'],
|
||||
['name' => 'amber', 'label' => 'Amber', 'desc' => 'Warm tones', 'gradient' => 'from-amber-400 to-orange-500'],
|
||||
['name' => 'jade', 'label' => 'Jade', 'desc' => 'Soft green', 'gradient' => 'from-teal-500 to-green-600'],
|
||||
['name' => 'onyx', 'label' => 'Onyx', 'desc' => 'Dark mode', 'gradient' => 'from-slate-700 to-slate-900'],
|
||||
['name' => 'crystal', 'label' => 'Crystal', 'desc' => 'Transparent', 'gradient' => 'from-cyan-400 to-blue-500'],
|
||||
['name' => 'aurora', 'label' => 'Aurora', 'desc' => 'Gradient effects', 'gradient' => 'from-green-400 via-blue-500 to-purple-500'],
|
||||
];
|
||||
@endphp
|
||||
|
||||
@foreach($themes as $theme)
|
||||
<div class="card group cursor-pointer" onclick="showNotification({type: 'success', message: 'This is the {{ $theme['label'] }} theme!', title: '{{ $theme['label'] }} Theme', theme: '{{ $theme['name'] }}'})">
|
||||
<div class="h-20 bg-gradient-to-br {{ $theme['gradient'] }} flex items-center justify-center">
|
||||
<span class="text-white text-2xl font-bold">{{ substr($theme['label'], 0, 1) }}</span>
|
||||
</div>
|
||||
<div class="p-4">
|
||||
<h3 class="font-semibold text-gray-800">{{ $theme['label'] }}</h3>
|
||||
<p class="text-sm text-gray-500">{{ $theme['desc'] }}</p>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
{{-- Usage Example --}}
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h2 class="text-xl font-bold text-gray-800">Using Themes</h2>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p class="text-gray-600 mb-4">Apply themes to your notifications with the <code class="bg-gray-100 px-2 py-1 rounded">use()</code> method.</p>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>PHP</span>
|
||||
</div>
|
||||
<pre class="!m-0"><code class="language-php">// Use a specific theme
|
||||
flash()->use('theme.material')->success('Material design notification!');
|
||||
|
||||
// Different themes for different messages
|
||||
flash()->use('theme.ios')->info('iOS style notification');
|
||||
flash()->use('theme.slack')->warning('Slack style warning');
|
||||
flash()->use('theme.amazon')->success('Amazon style success');
|
||||
|
||||
// Set default theme in config/flasher.php
|
||||
return [
|
||||
'default' => 'theme.material',
|
||||
];</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,200 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Notification Types')
|
||||
|
||||
@section('content')
|
||||
<div class="mb-8">
|
||||
<h1 class="section-title">Notification Types</h1>
|
||||
<p class="section-subtitle">PHPFlasher supports four notification types for different scenarios.</p>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-8">
|
||||
{{-- Success --}}
|
||||
<div class="card">
|
||||
<div class="h-2 bg-emerald-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<div class="flex items-center space-x-3">
|
||||
<div class="p-3 bg-emerald-100 rounded-xl">
|
||||
<svg class="w-8 h-8 text-emerald-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="text-2xl font-bold text-gray-800">Success</h2>
|
||||
<p class="text-gray-500">Positive feedback</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 mb-4">Use success notifications for completed actions, confirmations, and positive feedback.</p>
|
||||
|
||||
<div class="space-y-2 mb-6">
|
||||
<button onclick="showNotification({type: 'success', message: 'Your profile has been updated successfully!'})"
|
||||
class="btn btn-success w-full justify-start">
|
||||
Profile Updated
|
||||
</button>
|
||||
<button onclick="showNotification({type: 'success', message: 'Your account has been created. Welcome aboard!', title: 'Account Created'})"
|
||||
class="btn btn-success w-full justify-start">
|
||||
Account Created
|
||||
</button>
|
||||
<button onclick="showNotification({type: 'success', message: 'Payment of $99.00 confirmed. Receipt sent to your email.', title: 'Payment Successful'})"
|
||||
class="btn btn-success w-full justify-start">
|
||||
Payment Confirmed
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>PHP</span>
|
||||
</div>
|
||||
<pre class="!m-0"><code class="language-php">flash()->success('Profile updated successfully!');
|
||||
|
||||
// With title
|
||||
flash()->success('Welcome aboard!', 'Account Created');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Error --}}
|
||||
<div class="card">
|
||||
<div class="h-2 bg-rose-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<div class="flex items-center space-x-3">
|
||||
<div class="p-3 bg-rose-100 rounded-xl">
|
||||
<svg class="w-8 h-8 text-rose-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="text-2xl font-bold text-gray-800">Error</h2>
|
||||
<p class="text-gray-500">Failures and issues</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 mb-4">Use error notifications for validation failures, server errors, and problems.</p>
|
||||
|
||||
<div class="space-y-2 mb-6">
|
||||
<button onclick="showNotification({type: 'error', message: 'Invalid email or password. Please try again.'})"
|
||||
class="btn btn-danger w-full justify-start">
|
||||
Login Failed
|
||||
</button>
|
||||
<button onclick="showNotification({type: 'error', message: 'Your card was declined. Please try another payment method.', title: 'Payment Failed'})"
|
||||
class="btn btn-danger w-full justify-start">
|
||||
Payment Declined
|
||||
</button>
|
||||
<button onclick="showNotification({type: 'error', message: 'Unable to connect to server. Please check your connection.', title: 'Connection Error'})"
|
||||
class="btn btn-danger w-full justify-start">
|
||||
Server Error
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>PHP</span>
|
||||
</div>
|
||||
<pre class="!m-0"><code class="language-php">flash()->error('Invalid credentials.');
|
||||
|
||||
// With title
|
||||
flash()->error('Please try again.', 'Payment Failed');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Warning --}}
|
||||
<div class="card">
|
||||
<div class="h-2 bg-amber-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<div class="flex items-center space-x-3">
|
||||
<div class="p-3 bg-amber-100 rounded-xl">
|
||||
<svg class="w-8 h-8 text-amber-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="text-2xl font-bold text-gray-800">Warning</h2>
|
||||
<p class="text-gray-500">Caution alerts</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 mb-4">Use warning notifications to alert users about potential issues or important notices.</p>
|
||||
|
||||
<div class="space-y-2 mb-6">
|
||||
<button onclick="showNotification({type: 'warning', message: 'Your session will expire in 5 minutes.'})"
|
||||
class="btn btn-warning w-full justify-start">
|
||||
Session Expiring
|
||||
</button>
|
||||
<button onclick="showNotification({type: 'warning', message: 'You have unsaved changes that will be lost.', title: 'Unsaved Changes'})"
|
||||
class="btn btn-warning w-full justify-start">
|
||||
Unsaved Changes
|
||||
</button>
|
||||
<button onclick="showNotification({type: 'warning', message: 'Only 2 items left in stock!', title: 'Low Stock'})"
|
||||
class="btn btn-warning w-full justify-start">
|
||||
Low Stock Alert
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>PHP</span>
|
||||
</div>
|
||||
<pre class="!m-0"><code class="language-php">flash()->warning('Session expiring soon.');
|
||||
|
||||
// With title
|
||||
flash()->warning('Only 2 left!', 'Low Stock');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- Info --}}
|
||||
<div class="card">
|
||||
<div class="h-2 bg-sky-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<div class="flex items-center space-x-3">
|
||||
<div class="p-3 bg-sky-100 rounded-xl">
|
||||
<svg class="w-8 h-8 text-sky-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="text-2xl font-bold text-gray-800">Info</h2>
|
||||
<p class="text-gray-500">Neutral information</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 mb-4">Use info notifications for tips, updates, and general information.</p>
|
||||
|
||||
<div class="space-y-2 mb-6">
|
||||
<button onclick="showNotification({type: 'info', message: 'A new version is available. Click here to update.'})"
|
||||
class="btn btn-info w-full justify-start">
|
||||
Update Available
|
||||
</button>
|
||||
<button onclick="showNotification({type: 'info', message: 'Tip: You can use keyboard shortcuts for faster navigation.', title: 'Pro Tip'})"
|
||||
class="btn btn-info w-full justify-start">
|
||||
Helpful Tip
|
||||
</button>
|
||||
<button onclick="showNotification({type: 'info', message: 'Your report is being generated and will be ready shortly.'})"
|
||||
class="btn btn-info w-full justify-start">
|
||||
Processing Status
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>PHP</span>
|
||||
</div>
|
||||
<pre class="!m-0"><code class="language-php">flash()->info('New version available!');
|
||||
|
||||
// With title
|
||||
flash()->info('Use shortcuts!', 'Pro Tip');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
+13
-20
@@ -2,26 +2,19 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use App\Entity\Book;
|
||||
use App\Http\Controllers\DemoController;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
Route::get('/', function () {
|
||||
sweetalert()->timerProgressBar()->success('Your account has been successfully created!');
|
||||
noty()->layout('topCenter')->success('Welcome back, John Doe!');
|
||||
notyf()->ripple(false)->warning('Your subscription is about to expire in 3 days.');
|
||||
toastr()->positionClass('toast-bottom-left')->error('Payment failed. Please try again.');
|
||||
flash()->use('flasher')->success('Your profile has been updated successfully.');
|
||||
flash()->created(new Book('The Great Gatsby'));
|
||||
flash()->saved(new Book('1984'));
|
||||
session()->flash('success', 'Your settings have been saved.');
|
||||
return view('welcome');
|
||||
})->name('app_home');
|
||||
// Main pages
|
||||
Route::get('/', [DemoController::class, 'home'])->name('home');
|
||||
Route::get('/types', [DemoController::class, 'types'])->name('types');
|
||||
Route::get('/themes', [DemoController::class, 'themes'])->name('themes');
|
||||
Route::get('/adapters', [DemoController::class, 'adapters'])->name('adapters');
|
||||
Route::get('/positions', [DemoController::class, 'positions'])->name('positions');
|
||||
Route::get('/examples', [DemoController::class, 'examples'])->name('examples');
|
||||
Route::get('/playground', [DemoController::class, 'playground'])->name('playground');
|
||||
Route::get('/livewire', [DemoController::class, 'livewire'])->name('livewire');
|
||||
|
||||
Route::get('/redirect', function () {
|
||||
session()->flash('success', 'You have been redirected successfully.');
|
||||
return redirect('/destination');
|
||||
});
|
||||
|
||||
Route::get('/destination', function () {
|
||||
return view('welcome');
|
||||
});
|
||||
// AJAX endpoints
|
||||
Route::post('/notify', [DemoController::class, 'notify'])->name('notify');
|
||||
Route::post('/example/{scenario}', [DemoController::class, 'runExample'])->name('example.run');
|
||||
|
||||
@@ -0,0 +1,200 @@
|
||||
<?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;
|
||||
|
||||
final class DemoController extends AbstractController
|
||||
{
|
||||
#[Route('/', name: 'app_home')]
|
||||
public function home(): Response
|
||||
{
|
||||
return $this->render('home.html.twig');
|
||||
}
|
||||
|
||||
#[Route('/types', name: 'app_types')]
|
||||
public function types(): Response
|
||||
{
|
||||
return $this->render('types.html.twig');
|
||||
}
|
||||
|
||||
#[Route('/themes', name: 'app_themes')]
|
||||
public function themes(): Response
|
||||
{
|
||||
return $this->render('themes.html.twig');
|
||||
}
|
||||
|
||||
#[Route('/adapters', name: 'app_adapters')]
|
||||
public function adapters(): Response
|
||||
{
|
||||
return $this->render('adapters.html.twig');
|
||||
}
|
||||
|
||||
#[Route('/positions', name: 'app_positions')]
|
||||
public function positions(): Response
|
||||
{
|
||||
return $this->render('positions.html.twig');
|
||||
}
|
||||
|
||||
#[Route('/examples', name: 'app_examples')]
|
||||
public function examples(): Response
|
||||
{
|
||||
return $this->render('examples.html.twig');
|
||||
}
|
||||
|
||||
#[Route('/playground', name: 'app_playground')]
|
||||
public function playground(): Response
|
||||
{
|
||||
return $this->render('playground.html.twig');
|
||||
}
|
||||
|
||||
#[Route('/notify', name: 'app_notify', methods: ['POST'])]
|
||||
public function notify(Request $request): JsonResponse
|
||||
{
|
||||
$data = json_decode($request->getContent(), true);
|
||||
|
||||
$type = $data['type'] ?? 'success';
|
||||
$message = $data['message'] ?? 'Notification message';
|
||||
$title = $data['title'] ?? null;
|
||||
$theme = $data['theme'] ?? 'flasher';
|
||||
$adapter = $data['adapter'] ?? 'flasher';
|
||||
$position = $data['position'] ?? 'top-right';
|
||||
$timeout = (int) ($data['timeout'] ?? 5000);
|
||||
|
||||
$flasher = match ($adapter) {
|
||||
'toastr' => toastr(),
|
||||
'sweetalert' => sweetalert(),
|
||||
'noty' => noty(),
|
||||
'notyf' => notyf(),
|
||||
default => flash()->use("theme.{$theme}"),
|
||||
};
|
||||
|
||||
$options = [
|
||||
'position' => $position,
|
||||
'timeout' => $timeout,
|
||||
];
|
||||
|
||||
if ('toastr' === $adapter) {
|
||||
$options['positionClass'] = 'toast-'.str_replace('-', '-', $position);
|
||||
$options['timeOut'] = $timeout;
|
||||
} elseif ('noty' === $adapter) {
|
||||
$options['layout'] = match ($position) {
|
||||
'top-right' => 'topRight',
|
||||
'top-left' => 'topLeft',
|
||||
'top-center' => 'topCenter',
|
||||
'bottom-right' => 'bottomRight',
|
||||
'bottom-left' => 'bottomLeft',
|
||||
'bottom-center' => 'bottomCenter',
|
||||
default => 'topRight',
|
||||
};
|
||||
$options['timeout'] = $timeout;
|
||||
} elseif ('notyf' === $adapter) {
|
||||
$positionParts = explode('-', $position);
|
||||
$options['position'] = [
|
||||
'y' => $positionParts[0] ?? 'top',
|
||||
'x' => $positionParts[1] ?? 'right',
|
||||
];
|
||||
$options['duration'] = $timeout;
|
||||
}
|
||||
|
||||
if ($title) {
|
||||
$flasher->{$type}($message, $title, $options);
|
||||
} else {
|
||||
$flasher->{$type}($message, $options);
|
||||
}
|
||||
|
||||
return new JsonResponse(['success' => true]);
|
||||
}
|
||||
|
||||
#[Route('/example/{scenario}', name: 'app_example', methods: ['POST'])]
|
||||
public function runExample(string $scenario): JsonResponse
|
||||
{
|
||||
match ($scenario) {
|
||||
'registration' => $this->registrationExample(),
|
||||
'login_failed' => $this->loginFailedExample(),
|
||||
'validation' => $this->validationExample(),
|
||||
'shopping_cart' => $this->shoppingCartExample(),
|
||||
'file_upload' => $this->fileUploadExample(),
|
||||
'settings' => $this->settingsExample(),
|
||||
'payment_success' => $this->paymentSuccessExample(),
|
||||
'payment_failed' => $this->paymentFailedExample(),
|
||||
'delete_confirm' => $this->deleteConfirmExample(),
|
||||
'session_expiring' => $this->sessionExpiringExample(),
|
||||
default => flash()->info('Example not found'),
|
||||
};
|
||||
|
||||
return new JsonResponse(['success' => true]);
|
||||
}
|
||||
|
||||
private function registrationExample(): void
|
||||
{
|
||||
flash()->success('Welcome! Your account has been created.');
|
||||
flash()->info('Please check your email to verify your account.');
|
||||
}
|
||||
|
||||
private function loginFailedExample(): void
|
||||
{
|
||||
flash()->error('Invalid email or password.');
|
||||
flash()->info('Forgot your password? Click here to reset.');
|
||||
}
|
||||
|
||||
private function validationExample(): void
|
||||
{
|
||||
flash()->error('The email field is required.');
|
||||
flash()->error('Password must be at least 8 characters.');
|
||||
flash()->error('Please accept the terms and conditions.');
|
||||
}
|
||||
|
||||
private function shoppingCartExample(): void
|
||||
{
|
||||
flash()->success('iPhone 15 Pro added to cart!');
|
||||
flash()->warning('Only 2 items left in stock!');
|
||||
flash()->info('Add $20 more for free shipping!');
|
||||
}
|
||||
|
||||
private function fileUploadExample(): void
|
||||
{
|
||||
flash()->success('document.pdf uploaded successfully!');
|
||||
flash()->info('File size: 2.4 MB');
|
||||
}
|
||||
|
||||
private function settingsExample(): void
|
||||
{
|
||||
flash()->success('Settings saved successfully!');
|
||||
flash()->info('Some changes may require a page refresh.');
|
||||
}
|
||||
|
||||
private function paymentSuccessExample(): void
|
||||
{
|
||||
flash()->success('Payment of $149.99 confirmed!');
|
||||
flash()->info('Order #12345 - Receipt sent to your email.');
|
||||
}
|
||||
|
||||
private function paymentFailedExample(): void
|
||||
{
|
||||
flash()->error('Payment declined by your bank.');
|
||||
flash()->warning('Please try a different payment method.');
|
||||
flash()->info('Your cart has been saved.');
|
||||
}
|
||||
|
||||
private function deleteConfirmExample(): void
|
||||
{
|
||||
sweetalert()
|
||||
->showCancelButton()
|
||||
->confirmButtonText('Yes, delete it!')
|
||||
->cancelButtonText('Cancel')
|
||||
->warning('Are you sure? This cannot be undone.');
|
||||
}
|
||||
|
||||
private function sessionExpiringExample(): void
|
||||
{
|
||||
flash()->warning('Your session will expire in 5 minutes.');
|
||||
flash()->info('Click anywhere to stay logged in.');
|
||||
}
|
||||
}
|
||||
@@ -1,147 +0,0 @@
|
||||
<?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]);
|
||||
}
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
|
||||
class FeaturesController extends AbstractController
|
||||
{
|
||||
#[Route('/features', name: 'app_features')]
|
||||
public function index(): Response
|
||||
{
|
||||
// Demonstrate a few different notification types
|
||||
flash()->success('Explore the features of PHPFlasher!');
|
||||
flash()->option('timeout', 8000)
|
||||
->info('Click on the links to see each feature in action.');
|
||||
|
||||
return $this->render('features/index.html.twig');
|
||||
}
|
||||
|
||||
#[Route('/features/types', name: 'app_types')]
|
||||
public function types(): Response
|
||||
{
|
||||
// Demonstrate different notification types
|
||||
flash()->success('This is a success notification!');
|
||||
flash()->info('This is an info notification!');
|
||||
flash()->warning('This is a warning notification!');
|
||||
flash()->error('This is an error notification!');
|
||||
|
||||
return $this->render('features/types.html.twig');
|
||||
}
|
||||
|
||||
#[Route('/features/positions', name: 'app_positions')]
|
||||
public function positions(): Response
|
||||
{
|
||||
// Notifications with different positions
|
||||
flash()->option('position', 'top-right')->success('This notification appears in the top-right corner!');
|
||||
|
||||
return $this->render('features/positions.html.twig');
|
||||
}
|
||||
|
||||
#[Route('/features/options', name: 'app_options')]
|
||||
public function options(): Response
|
||||
{
|
||||
// Notification with custom options
|
||||
flash()->option('timeout', 8000)
|
||||
->option('position', 'bottom-center')
|
||||
->option('showProgressbar', true)
|
||||
->success('This notification has custom options!');
|
||||
|
||||
return $this->render('features/options.html.twig');
|
||||
}
|
||||
|
||||
#[Route('/features/plugins', name: 'app_plugins')]
|
||||
public function plugins(): Response
|
||||
{
|
||||
// Plugin examples
|
||||
flash()->addSuccess('This shows how PHPFlasher can be extended with plugins!');
|
||||
|
||||
return $this->render('features/plugins.html.twig');
|
||||
}
|
||||
|
||||
#[Route('/features/presets', name: 'app_presets')]
|
||||
public function presets(): Response
|
||||
{
|
||||
// Example of using presets
|
||||
flash()->preset('profile.updated')
|
||||
->success('Your profile has been updated successfully!');
|
||||
|
||||
flash()->preset('item.deleted')
|
||||
->info('The item has been deleted.');
|
||||
|
||||
return $this->render('features/presets.html.twig');
|
||||
}
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
<?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 HomeController extends AbstractController
|
||||
{
|
||||
#[Route('/', name: 'app_home')]
|
||||
public function index(): Response
|
||||
{
|
||||
// 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']);
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
<?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');
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
|
||||
class ThemesController extends AbstractController
|
||||
{
|
||||
#[Route('/themes', name: 'app_themes')]
|
||||
public function index(): Response
|
||||
{
|
||||
// Show default theme notification
|
||||
flash()->success('This is a notification with the default theme!');
|
||||
|
||||
return $this->render('themes/index.html.twig');
|
||||
}
|
||||
|
||||
#[Route('/themes/flasher', name: 'app_theme_flasher')]
|
||||
public function flasherTheme(): Response
|
||||
{
|
||||
// Using the Flasher theme
|
||||
flash()->option('theme', 'flasher')
|
||||
->success('This notification uses the Flasher theme!');
|
||||
|
||||
return $this->render('themes/flasher.html.twig');
|
||||
}
|
||||
|
||||
#[Route('/themes/crystal', name: 'app_theme_crystal')]
|
||||
public function crystalTheme(): Response
|
||||
{
|
||||
// Using the Crystal theme
|
||||
flash()->option('theme', 'crystal')
|
||||
->success('This notification uses the Crystal theme!');
|
||||
|
||||
return $this->render('themes/crystal.html.twig');
|
||||
}
|
||||
|
||||
#[Route('/themes/emerald', name: 'app_theme_emerald')]
|
||||
public function emeraldTheme(): Response
|
||||
{
|
||||
// Using the Emerald theme
|
||||
flash()->option('theme', 'emerald')
|
||||
->success('This notification uses the Emerald theme!');
|
||||
|
||||
return $this->render('themes/emerald.html.twig');
|
||||
}
|
||||
|
||||
#[Route('/themes/sapphire', name: 'app_theme_sapphire')]
|
||||
public function sapphireTheme(): Response
|
||||
{
|
||||
// Using the Sapphire theme
|
||||
flash()->option('theme', 'sapphire')
|
||||
->success('This notification uses the Sapphire theme!');
|
||||
|
||||
return $this->render('themes/sapphire.html.twig');
|
||||
}
|
||||
|
||||
#[Route('/themes/amazon', name: 'app_theme_amazon')]
|
||||
public function amazonTheme(): Response
|
||||
{
|
||||
// Using the Amazon theme
|
||||
flash()->option('theme', 'amazon')
|
||||
->success('This notification uses the Amazon theme!');
|
||||
|
||||
return $this->render('themes/amazon.html.twig');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,243 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block title %}Adapters{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="mb-8">
|
||||
<h1 class="section-title">Notification Adapters</h1>
|
||||
<p class="section-subtitle">PHPFlasher supports multiple notification libraries. Choose your favorite!</p>
|
||||
</div>
|
||||
|
||||
<div class="space-y-8">
|
||||
{# Flasher (Default) #}
|
||||
<div class="card">
|
||||
<div class="h-2 bg-gradient-to-r from-indigo-500 to-purple-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center space-x-3 mb-4">
|
||||
<div class="p-3 bg-indigo-100 rounded-xl">
|
||||
<svg class="w-8 h-8 text-indigo-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="text-2xl font-bold text-gray-800">Flasher</h2>
|
||||
<p class="text-gray-500">Default adapter with 17+ themes</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 mb-4">The default PHPFlasher adapter with beautiful built-in themes. No additional JavaScript libraries required.</p>
|
||||
|
||||
<div class="flex flex-wrap gap-2 mb-6">
|
||||
<button onclick="showNotification({type: 'success', message: 'This is the default Flasher notification!', adapter: 'flasher'})"
|
||||
class="btn btn-success">Success</button>
|
||||
<button onclick="showNotification({type: 'error', message: 'Error notification with Flasher', adapter: 'flasher'})"
|
||||
class="btn btn-danger">Error</button>
|
||||
<button onclick="showNotification({type: 'warning', message: 'Warning notification with Flasher', adapter: 'flasher'})"
|
||||
class="btn btn-warning">Warning</button>
|
||||
<button onclick="showNotification({type: 'info', message: 'Info notification with Flasher', adapter: 'flasher'})"
|
||||
class="btn btn-info">Info</button>
|
||||
</div>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header"><span>Installation</span></div>
|
||||
<pre class="!m-0"><code class="language-bash">composer require php-flasher/flasher-symfony</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header"><span>Usage</span></div>
|
||||
<pre class="!m-0"><code class="language-php">flash()->success('Operation completed!');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# Toastr #}
|
||||
<div class="card">
|
||||
<div class="h-2 bg-gradient-to-r from-sky-500 to-blue-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center space-x-3 mb-4">
|
||||
<div class="p-3 bg-sky-100 rounded-xl">
|
||||
<svg class="w-8 h-8 text-sky-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="text-2xl font-bold text-gray-800">Toastr</h2>
|
||||
<p class="text-gray-500">Simple, elegant toast notifications</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 mb-4">Classic toast notifications with smooth animations. One of the most popular notification libraries.</p>
|
||||
|
||||
<div class="flex flex-wrap gap-2 mb-6">
|
||||
<button onclick="showNotification({type: 'success', message: 'Toastr success notification!', adapter: 'toastr'})"
|
||||
class="btn btn-success">Success</button>
|
||||
<button onclick="showNotification({type: 'error', message: 'Toastr error notification!', adapter: 'toastr'})"
|
||||
class="btn btn-danger">Error</button>
|
||||
<button onclick="showNotification({type: 'warning', message: 'Toastr warning notification!', adapter: 'toastr'})"
|
||||
class="btn btn-warning">Warning</button>
|
||||
<button onclick="showNotification({type: 'info', message: 'Toastr info notification!', adapter: 'toastr'})"
|
||||
class="btn btn-info">Info</button>
|
||||
</div>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header"><span>Installation</span></div>
|
||||
<pre class="!m-0"><code class="language-bash">composer require php-flasher/flasher-toastr-symfony</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header"><span>Usage</span></div>
|
||||
<pre class="!m-0"><code class="language-php">toastr()->success('Data saved successfully!');
|
||||
|
||||
// With options
|
||||
toastr()
|
||||
->closeButton()
|
||||
->progressBar()
|
||||
->positionClass('toast-top-right')
|
||||
->success('Profile updated!');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# SweetAlert #}
|
||||
<div class="card">
|
||||
<div class="h-2 bg-gradient-to-r from-pink-500 to-rose-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center space-x-3 mb-4">
|
||||
<div class="p-3 bg-pink-100 rounded-xl">
|
||||
<svg class="w-8 h-8 text-pink-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="text-2xl font-bold text-gray-800">SweetAlert 2</h2>
|
||||
<p class="text-gray-500">Beautiful, responsive, customizable alerts</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 mb-4">Feature-rich modal dialogs with confirmations, inputs, and beautiful animations. Perfect for important user interactions.</p>
|
||||
|
||||
<div class="flex flex-wrap gap-2 mb-6">
|
||||
<button onclick="showNotification({type: 'success', message: 'SweetAlert success!', title: 'Success', adapter: 'sweetalert'})"
|
||||
class="btn btn-success">Success</button>
|
||||
<button onclick="showNotification({type: 'error', message: 'SweetAlert error message', title: 'Error', adapter: 'sweetalert'})"
|
||||
class="btn btn-danger">Error</button>
|
||||
<button onclick="showNotification({type: 'warning', message: 'Are you sure you want to proceed?', title: 'Warning', adapter: 'sweetalert'})"
|
||||
class="btn btn-warning">Warning</button>
|
||||
<button onclick="showNotification({type: 'info', message: 'Here is some information', title: 'Info', adapter: 'sweetalert'})"
|
||||
class="btn btn-info">Info</button>
|
||||
</div>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header"><span>Installation</span></div>
|
||||
<pre class="!m-0"><code class="language-bash">composer require php-flasher/flasher-sweetalert-symfony</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header"><span>Usage</span></div>
|
||||
<pre class="!m-0"><code class="language-php">sweetalert()->success('Great job!', 'Success');
|
||||
|
||||
// Confirmation dialog
|
||||
sweetalert()
|
||||
->showDenyButton()
|
||||
->showCancelButton()
|
||||
->confirmButtonText('Save')
|
||||
->denyButtonText("Don't save")
|
||||
->warning('Do you want to save the changes?');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# Noty #}
|
||||
<div class="card">
|
||||
<div class="h-2 bg-gradient-to-r from-emerald-500 to-teal-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center space-x-3 mb-4">
|
||||
<div class="p-3 bg-emerald-100 rounded-xl">
|
||||
<svg class="w-8 h-8 text-emerald-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="text-2xl font-bold text-gray-800">Noty</h2>
|
||||
<p class="text-gray-500">Dependency-free notification library</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 mb-4">A flexible, dependency-free notification library with multiple layouts and themes.</p>
|
||||
|
||||
<div class="flex flex-wrap gap-2 mb-6">
|
||||
<button onclick="showNotification({type: 'success', message: 'Noty success notification!', adapter: 'noty'})"
|
||||
class="btn btn-success">Success</button>
|
||||
<button onclick="showNotification({type: 'error', message: 'Noty error notification!', adapter: 'noty'})"
|
||||
class="btn btn-danger">Error</button>
|
||||
<button onclick="showNotification({type: 'warning', message: 'Noty warning notification!', adapter: 'noty'})"
|
||||
class="btn btn-warning">Warning</button>
|
||||
<button onclick="showNotification({type: 'info', message: 'Noty info notification!', adapter: 'noty'})"
|
||||
class="btn btn-info">Info</button>
|
||||
</div>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header"><span>Installation</span></div>
|
||||
<pre class="!m-0"><code class="language-bash">composer require php-flasher/flasher-noty-symfony</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header"><span>Usage</span></div>
|
||||
<pre class="!m-0"><code class="language-php">noty()->success('Data saved!');
|
||||
|
||||
// With layout options
|
||||
noty()
|
||||
->layout('topCenter')
|
||||
->timeout(3000)
|
||||
->progressBar()
|
||||
->info('Processing your request...');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# Notyf #}
|
||||
<div class="card">
|
||||
<div class="h-2 bg-gradient-to-r from-amber-500 to-orange-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center space-x-3 mb-4">
|
||||
<div class="p-3 bg-amber-100 rounded-xl">
|
||||
<svg class="w-8 h-8 text-amber-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 7h8m0 0v8m0-8l-8 8-4-4-6 6"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="text-2xl font-bold text-gray-800">Notyf</h2>
|
||||
<p class="text-gray-500">Minimalist, responsive notifications</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 mb-4">A minimalist JavaScript library for toast notifications. Tiny footprint with smooth animations.</p>
|
||||
|
||||
<div class="flex flex-wrap gap-2 mb-6">
|
||||
<button onclick="showNotification({type: 'success', message: 'Notyf success notification!', adapter: 'notyf'})"
|
||||
class="btn btn-success">Success</button>
|
||||
<button onclick="showNotification({type: 'error', message: 'Notyf error notification!', adapter: 'notyf'})"
|
||||
class="btn btn-danger">Error</button>
|
||||
</div>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header"><span>Installation</span></div>
|
||||
<pre class="!m-0"><code class="language-bash">composer require php-flasher/flasher-notyf-symfony</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header"><span>Usage</span></div>
|
||||
<pre class="!m-0"><code class="language-php">notyf()->success('Minimal and clean!');
|
||||
|
||||
// With options
|
||||
notyf()
|
||||
->position('x', 'right')
|
||||
->position('y', 'top')
|
||||
->dismissible(true)
|
||||
->ripple(true)
|
||||
->success('File uploaded successfully!');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{% block title %}PHPFlasher Demo{% endblock %}</title>
|
||||
<title>{% block title %}PHPFlasher Demo{% endblock %} - Symfony</title>
|
||||
|
||||
{# Tailwind CSS v4 CDN #}
|
||||
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
|
||||
@@ -12,11 +12,11 @@
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-tomorrow.min.css">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/toolbar/prism-toolbar.min.css">
|
||||
|
||||
{# Custom styles using Tailwind #}
|
||||
{# Custom Tailwind components #}
|
||||
<script type="text/tailwindcss">
|
||||
@layer components {
|
||||
.btn {
|
||||
@apply px-4 py-2 rounded-md font-medium transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-opacity-50;
|
||||
@apply px-4 py-2 rounded-lg font-medium transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-opacity-50 inline-flex items-center justify-center gap-2;
|
||||
}
|
||||
.btn-primary {
|
||||
@apply bg-indigo-600 text-white hover:bg-indigo-700 focus:ring-indigo-500;
|
||||
@@ -36,17 +36,35 @@
|
||||
.btn-outline {
|
||||
@apply border border-gray-300 text-gray-700 bg-white hover:bg-gray-50 focus:ring-indigo-500;
|
||||
}
|
||||
.btn-sm {
|
||||
@apply px-3 py-1.5 text-sm;
|
||||
}
|
||||
.card {
|
||||
@apply bg-white rounded-xl shadow-md overflow-hidden hover:shadow-lg transition-shadow duration-300;
|
||||
}
|
||||
.card-header {
|
||||
@apply px-6 py-4 border-b border-gray-100;
|
||||
}
|
||||
.card-body {
|
||||
@apply p-6;
|
||||
}
|
||||
.code-block {
|
||||
@apply rounded-lg overflow-hidden shadow-lg my-6;
|
||||
@apply rounded-lg overflow-hidden shadow-lg my-4;
|
||||
}
|
||||
.code-header {
|
||||
@apply bg-gray-800 text-gray-200 px-4 py-2 flex justify-between items-center;
|
||||
@apply bg-gray-800 text-gray-300 px-4 py-2 flex justify-between items-center text-sm;
|
||||
}
|
||||
.theme-card {
|
||||
@apply rounded-lg overflow-hidden bg-white shadow-md hover:shadow-lg transition duration-300;
|
||||
.section-title {
|
||||
@apply text-2xl font-bold text-gray-800 mb-2;
|
||||
}
|
||||
.theme-preview {
|
||||
@apply h-32 flex items-center justify-center;
|
||||
.section-subtitle {
|
||||
@apply text-gray-600 mb-6;
|
||||
}
|
||||
.nav-link {
|
||||
@apply px-3 py-2 rounded-lg text-gray-600 hover:text-indigo-600 hover:bg-indigo-50 transition-colors font-medium;
|
||||
}
|
||||
.nav-link-active {
|
||||
@apply text-indigo-600 bg-indigo-50;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -54,176 +72,127 @@
|
||||
{% block stylesheets %}{% endblock %}
|
||||
</head>
|
||||
<body class="bg-gray-50 antialiased text-gray-900 min-h-screen flex flex-col">
|
||||
<header class="bg-indigo-600 text-white shadow-md">
|
||||
{# Header #}
|
||||
<header class="bg-white border-b border-gray-200 sticky top-0 z-50">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex justify-between items-center py-4">
|
||||
<div class="flex items-center space-x-3">
|
||||
<div class="flex items-center">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-8 w-8" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M13 10V3L4 14h7v7l9-11h-7z" />
|
||||
</svg>
|
||||
<span class="ml-2 text-2xl font-bold">PHPFlasher</span>
|
||||
</div>
|
||||
<span class="hidden md:inline text-indigo-200">Beautiful Notifications for Your PHP Applications</span>
|
||||
</div>
|
||||
<div class="hidden md:flex space-x-4">
|
||||
<a href="https://github.com/php-flasher/flasher" class="text-indigo-100 hover:text-white transition flex items-center" target="_blank">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-1" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/>
|
||||
</svg>
|
||||
GitHub
|
||||
<div class="flex justify-between items-center h-16">
|
||||
{# Logo #}
|
||||
<a href="{{ path('app_home') }}" class="flex items-center space-x-2">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-8 w-8 text-indigo-600" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M13 10V3L4 14h7v7l9-11h-7z" />
|
||||
</svg>
|
||||
<span class="text-xl font-bold text-gray-900">PHPFlasher</span>
|
||||
<span class="hidden sm:inline-block px-2 py-0.5 text-xs font-medium bg-emerald-100 text-emerald-600 rounded-full">Symfony</span>
|
||||
</a>
|
||||
|
||||
{# Desktop Navigation #}
|
||||
<nav class="hidden md:flex items-center space-x-1">
|
||||
<a href="{{ path('app_home') }}" class="nav-link {% if app.request.get('_route') == 'app_home' %}nav-link-active{% endif %}">Home</a>
|
||||
<a href="{{ path('app_types') }}" class="nav-link {% if app.request.get('_route') == 'app_types' %}nav-link-active{% endif %}">Types</a>
|
||||
<a href="{{ path('app_themes') }}" class="nav-link {% if app.request.get('_route') == 'app_themes' %}nav-link-active{% endif %}">Themes</a>
|
||||
<a href="{{ path('app_adapters') }}" class="nav-link {% if app.request.get('_route') == 'app_adapters' %}nav-link-active{% endif %}">Adapters</a>
|
||||
<a href="{{ path('app_positions') }}" class="nav-link {% if app.request.get('_route') == 'app_positions' %}nav-link-active{% endif %}">Positions</a>
|
||||
<a href="{{ path('app_examples') }}" class="nav-link {% if app.request.get('_route') == 'app_examples' %}nav-link-active{% endif %}">Examples</a>
|
||||
<a href="{{ path('app_playground') }}" class="nav-link {% if app.request.get('_route') == 'app_playground' %}nav-link-active{% endif %}">Playground</a>
|
||||
</nav>
|
||||
|
||||
{# External Links #}
|
||||
<div class="hidden md:flex items-center space-x-3">
|
||||
<a href="https://github.com/php-flasher/php-flasher" target="_blank" class="text-gray-500 hover:text-gray-700">
|
||||
<svg class="h-5 w-5" fill="currentColor" viewBox="0 0 24 24"><path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/></svg>
|
||||
</a>
|
||||
<a href="https://php-flasher.io" class="text-indigo-100 hover:text-white transition flex items-center" target="_blank">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-1" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 12a9 9 0 01-9 9m9-9a9 9 0 00-9-9m9 9H3m9 9a9 9 0 01-9-9m9 9c1.657 0 3-4.03 3-9s-1.343-9-3-9m0 18c-1.657 0-3-4.03-3-9s1.343-9 3-9m-9 9a9 9 0 019-9" />
|
||||
</svg>
|
||||
<a href="https://php-flasher.io" target="_blank" class="btn btn-primary btn-sm">
|
||||
Documentation
|
||||
</a>
|
||||
</div>
|
||||
<button id="mobile-menu-button" class="md:hidden text-white">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
|
||||
{# Mobile menu button #}
|
||||
<button id="mobile-menu-btn" class="md:hidden p-2 rounded-lg text-gray-500 hover:bg-gray-100">
|
||||
<svg class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# Mobile Navigation #}
|
||||
<div id="mobile-menu" class="hidden md:hidden border-t border-gray-200 bg-white">
|
||||
<div class="px-4 py-3 space-y-1">
|
||||
<a href="{{ path('app_home') }}" class="block px-3 py-2 rounded-lg {% if app.request.get('_route') == 'app_home' %}bg-indigo-50 text-indigo-600{% else %}text-gray-600 hover:bg-gray-50{% endif %}">Home</a>
|
||||
<a href="{{ path('app_types') }}" class="block px-3 py-2 rounded-lg {% if app.request.get('_route') == 'app_types' %}bg-indigo-50 text-indigo-600{% else %}text-gray-600 hover:bg-gray-50{% endif %}">Types</a>
|
||||
<a href="{{ path('app_themes') }}" class="block px-3 py-2 rounded-lg {% if app.request.get('_route') == 'app_themes' %}bg-indigo-50 text-indigo-600{% else %}text-gray-600 hover:bg-gray-50{% endif %}">Themes</a>
|
||||
<a href="{{ path('app_adapters') }}" class="block px-3 py-2 rounded-lg {% if app.request.get('_route') == 'app_adapters' %}bg-indigo-50 text-indigo-600{% else %}text-gray-600 hover:bg-gray-50{% endif %}">Adapters</a>
|
||||
<a href="{{ path('app_positions') }}" class="block px-3 py-2 rounded-lg {% if app.request.get('_route') == 'app_positions' %}bg-indigo-50 text-indigo-600{% else %}text-gray-600 hover:bg-gray-50{% endif %}">Positions</a>
|
||||
<a href="{{ path('app_examples') }}" class="block px-3 py-2 rounded-lg {% if app.request.get('_route') == 'app_examples' %}bg-indigo-50 text-indigo-600{% else %}text-gray-600 hover:bg-gray-50{% endif %}">Examples</a>
|
||||
<a href="{{ path('app_playground') }}" class="block px-3 py-2 rounded-lg {% if app.request.get('_route') == 'app_playground' %}bg-indigo-50 text-indigo-600{% else %}text-gray-600 hover:bg-gray-50{% endif %}">Playground</a>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div id="mobile-menu" class="hidden md:hidden bg-indigo-700 text-white">
|
||||
<div class="px-4 pt-2 pb-4 space-y-3">
|
||||
<a href="{{ path('app_home') }}" class="block py-2 hover:bg-indigo-600 rounded px-2">Home</a>
|
||||
<a href="{{ path('app_features') }}" class="block py-2 hover:bg-indigo-600 rounded px-2">Features</a>
|
||||
<a href="{{ path('app_themes') }}" class="block py-2 hover:bg-indigo-600 rounded px-2">Themes</a>
|
||||
<a href="{{ path('app_examples') }}" class="block py-2 hover:bg-indigo-600 rounded px-2">Examples</a>
|
||||
<a href="{{ path('app_playground') }}" class="block py-2 hover:bg-indigo-600 rounded px-2">Playground</a>
|
||||
<a href="https://github.com/php-flasher/flasher" class="block py-2 hover:bg-indigo-600 rounded px-2">GitHub</a>
|
||||
<a href="https://php-flasher.io" class="block py-2 hover:bg-indigo-600 rounded px-2">Documentation</a>
|
||||
{# Main Content #}
|
||||
<main class="flex-1">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
||||
{% block content %}{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-1">
|
||||
<aside class="hidden md:block bg-white w-64 border-r border-gray-200 shadow-sm">
|
||||
<div class="p-6 border-b border-gray-200">
|
||||
<h2 class="text-lg font-semibold text-gray-800">Navigation</h2>
|
||||
<p class="text-sm text-gray-500 mt-1">Explore PHPFlasher</p>
|
||||
</div>
|
||||
<nav class="py-4">
|
||||
<div class="px-6 py-2 text-xs font-semibold text-gray-500 uppercase tracking-wider">
|
||||
Getting Started
|
||||
</div>
|
||||
<a href="{{ path('app_home') }}" class="block px-6 py-2 text-gray-700 hover:bg-indigo-50 hover:text-indigo-700 {% if app.request.get('_route') == 'app_home' %}bg-indigo-50 text-indigo-700 border-r-4 border-indigo-500{% endif %}">
|
||||
Home
|
||||
</a>
|
||||
<a href="{{ path('app_installation') }}" class="block px-6 py-2 text-gray-700 hover:bg-indigo-50 hover:text-indigo-700 {% if app.request.get('_route') == 'app_installation' %}bg-indigo-50 text-indigo-700 border-r-4 border-indigo-500{% endif %}">
|
||||
Installation
|
||||
</a>
|
||||
<a href="{{ path('app_basic_usage') }}" class="block px-6 py-2 text-gray-700 hover:bg-indigo-50 hover:text-indigo-700 {% if app.request.get('_route') == 'app_basic_usage' %}bg-indigo-50 text-indigo-700 border-r-4 border-indigo-500{% endif %}">
|
||||
Basic Usage
|
||||
</a>
|
||||
|
||||
<div class="px-6 py-2 mt-4 text-xs font-semibold text-gray-500 uppercase tracking-wider">
|
||||
Features
|
||||
</div>
|
||||
<a href="{{ path('app_types') }}" class="block px-6 py-2 text-gray-700 hover:bg-indigo-50 hover:text-indigo-700 {% if app.request.get('_route') == 'app_types' %}bg-indigo-50 text-indigo-700 border-r-4 border-indigo-500{% endif %}">
|
||||
Notification Types
|
||||
</a>
|
||||
<a href="{{ path('app_positions') }}" class="block px-6 py-2 text-gray-700 hover:bg-indigo-50 hover:text-indigo-700 {% if app.request.get('_route') == 'app_positions' %}bg-indigo-50 text-indigo-700 border-r-4 border-indigo-500{% endif %}">
|
||||
Positions
|
||||
</a>
|
||||
<a href="{{ path('app_themes') }}" class="block px-6 py-2 text-gray-700 hover:bg-indigo-50 hover:text-indigo-700 {% if app.request.get('_route') == 'app_themes' %}bg-indigo-50 text-indigo-700 border-r-4 border-indigo-500{% endif %}">
|
||||
Themes
|
||||
</a>
|
||||
<a href="{{ path('app_options') }}" class="block px-6 py-2 text-gray-700 hover:bg-indigo-50 hover:text-indigo-700 {% if app.request.get('_route') == 'app_options' %}bg-indigo-50 text-indigo-700 border-r-4 border-indigo-500{% endif %}">
|
||||
Options & Configuration
|
||||
</a>
|
||||
<a href="{{ path('app_plugins') }}" class="block px-6 py-2 text-gray-700 hover:bg-indigo-50 hover:text-indigo-700 {% if app.request.get('_route') == 'app_plugins' %}bg-indigo-50 text-indigo-700 border-r-4 border-indigo-500{% endif %}">
|
||||
Plugins
|
||||
</a>
|
||||
|
||||
<div class="px-6 py-2 mt-4 text-xs font-semibold text-gray-500 uppercase tracking-wider">
|
||||
Examples
|
||||
</div>
|
||||
<a href="{{ path('app_form_example') }}" class="block px-6 py-2 text-gray-700 hover:bg-indigo-50 hover:text-indigo-700 {% if app.request.get('_route') == 'app_form_example' %}bg-indigo-50 text-indigo-700 border-r-4 border-indigo-500{% endif %}">
|
||||
Form Validation
|
||||
</a>
|
||||
<a href="{{ path('app_ajax_example') }}" class="block px-6 py-2 text-gray-700 hover:bg-indigo-50 hover:text-indigo-700 {% if app.request.get('_route') == 'app_ajax_example' %}bg-indigo-50 text-indigo-700 border-r-4 border-indigo-500{% endif %}">
|
||||
AJAX Requests
|
||||
</a>
|
||||
<a href="{{ path('app_presets') }}" class="block px-6 py-2 text-gray-700 hover:bg-indigo-50 hover:text-indigo-700 {% if app.request.get('_route') == 'app_presets' %}bg-indigo-50 text-indigo-700 border-r-4 border-indigo-500{% endif %}">
|
||||
Presets
|
||||
</a>
|
||||
<a href="{{ path('app_real_world') }}" class="block px-6 py-2 text-gray-700 hover:bg-indigo-50 hover:text-indigo-700 {% if app.request.get('_route') == 'app_real_world' %}bg-indigo-50 text-indigo-700 border-r-4 border-indigo-500{% endif %}">
|
||||
Real-World Examples
|
||||
</a>
|
||||
|
||||
<div class="px-6 py-2 mt-4 text-xs font-semibold text-gray-500 uppercase tracking-wider">
|
||||
Interactive
|
||||
</div>
|
||||
<a href="{{ path('app_playground') }}" class="block px-6 py-2 text-gray-700 hover:bg-indigo-50 hover:text-indigo-700 {% if app.request.get('_route') == 'app_playground' %}bg-indigo-50 text-indigo-700 border-r-4 border-indigo-500{% endif %}">
|
||||
Interactive Playground
|
||||
</a>
|
||||
<a href="{{ path('app_theme_builder') }}" class="block px-6 py-2 text-gray-700 hover:bg-indigo-50 hover:text-indigo-700 {% if app.request.get('_route') == 'app_theme_builder' %}bg-indigo-50 text-indigo-700 border-r-4 border-indigo-500{% endif %}">
|
||||
Theme Builder
|
||||
</a>
|
||||
</nav>
|
||||
</aside>
|
||||
|
||||
<main class="flex-1 overflow-x-hidden">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
||||
<div class="mb-6">
|
||||
<h1 class="text-3xl font-bold text-gray-900">{% block page_title %}Welcome to PHPFlasher{% endblock %}</h1>
|
||||
<p class="mt-2 text-lg text-gray-600">{% block page_subtitle %}A powerful notification system for PHP applications{% endblock %}</p>
|
||||
</div>
|
||||
|
||||
{% block content %}{% endblock %}
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
{# Footer #}
|
||||
<footer class="bg-white border-t border-gray-200 mt-auto">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6">
|
||||
<div class="flex flex-col md:flex-row justify-between items-center space-y-4 md:space-y-0">
|
||||
<div class="text-center md:text-left">
|
||||
<p class="text-gray-500">
|
||||
© {{ "now"|date("Y") }} PHPFlasher. Made with ❤️ by <a href="https://github.com/yoeunes" class="text-indigo-600 hover:text-indigo-500">Younes ENNAJI</a>
|
||||
</p>
|
||||
<div class="flex items-center space-x-2 text-gray-500">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M13 10V3L4 14h7v7l9-11h-7z" />
|
||||
</svg>
|
||||
<span>PHPFlasher Demo</span>
|
||||
</div>
|
||||
<div class="flex space-x-6">
|
||||
<a href="https://github.com/php-flasher/flasher" class="text-gray-500 hover:text-gray-700">
|
||||
<span class="sr-only">GitHub</span>
|
||||
<svg class="h-6 w-6" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path fill-rule="evenodd" d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z" clip-rule="evenodd"></path>
|
||||
</svg>
|
||||
</a>
|
||||
<a href="https://php-flasher.io" class="text-gray-500 hover:text-gray-700">
|
||||
<span class="sr-only">Website</span>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3.055 11H5a2 2 0 012 2v1a2 2 0 002 2 2 2 0 012 2v2.945M8 3.935V5.5A2.5 2.5 0 0010.5 8h.5a2 2 0 012 2 2 2 0 104 0 2 2 0 012-2h1.064M15 20.488V18a2 2 0 012-2h3.064M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
</a>
|
||||
<div class="flex items-center space-x-6 text-sm text-gray-500">
|
||||
<a href="https://php-flasher.io" target="_blank" class="hover:text-indigo-600">Documentation</a>
|
||||
<a href="https://github.com/php-flasher/php-flasher" target="_blank" class="hover:text-indigo-600">GitHub</a>
|
||||
<span>Made with ❤️ by <a href="https://github.com/yoeunes" target="_blank" class="hover:text-indigo-600">Younes</a></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
{# Prism.js for syntax highlighting #}
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-core.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/autoloader/prism-autoloader.min.js"></script>
|
||||
{# Scripts #}
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/prism.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-php.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/toolbar/prism-toolbar.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/copy-to-clipboard/prism-copy-to-clipboard.min.js"></script>
|
||||
|
||||
{# Mobile menu toggle script #}
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const mobileMenuButton = document.getElementById('mobile-menu-button');
|
||||
const mobileMenu = document.getElementById('mobile-menu');
|
||||
|
||||
if (mobileMenuButton && mobileMenu) {
|
||||
mobileMenuButton.addEventListener('click', function() {
|
||||
mobileMenu.classList.toggle('hidden');
|
||||
});
|
||||
}
|
||||
// Mobile menu toggle
|
||||
document.getElementById('mobile-menu-btn')?.addEventListener('click', function() {
|
||||
document.getElementById('mobile-menu')?.classList.toggle('hidden');
|
||||
});
|
||||
|
||||
// Helper function for notifications via AJAX
|
||||
window.showNotification = async function(options) {
|
||||
const response = await fetch('{{ path("app_notify") }}', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json',
|
||||
'X-Requested-With': 'XMLHttpRequest',
|
||||
},
|
||||
body: JSON.stringify(options),
|
||||
});
|
||||
return response.json();
|
||||
};
|
||||
|
||||
// Helper function for running examples
|
||||
window.runExample = async function(scenario) {
|
||||
const response = await fetch('/example/' + scenario, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json',
|
||||
'X-Requested-With': 'XMLHttpRequest',
|
||||
},
|
||||
});
|
||||
return response.json();
|
||||
};
|
||||
</script>
|
||||
|
||||
{% block javascripts %}{% endblock %}
|
||||
|
||||
@@ -0,0 +1,215 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block title %}Real-World Examples{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="mb-8">
|
||||
<h1 class="section-title">Real-World Examples</h1>
|
||||
<p class="section-subtitle">See how PHPFlasher handles common application scenarios. Click to run each example.</p>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||
{# User Registration #}
|
||||
<div class="card">
|
||||
<div class="h-2 bg-gradient-to-r from-emerald-500 to-green-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center space-x-3 mb-4">
|
||||
<div class="p-3 bg-emerald-100 rounded-xl">
|
||||
<svg class="w-6 h-6 text-emerald-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M18 9v3m0 0v3m0-3h3m-3 0h-3m-2-5a4 4 0 11-8 0 4 4 0 018 0zM3 20a6 6 0 0112 0v1H3v-1z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-lg font-bold text-gray-800">User Registration</h3>
|
||||
<p class="text-sm text-gray-500">Account creation flow</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 mb-4">Simulates a successful user registration with welcome message and email verification notice.</p>
|
||||
|
||||
<button onclick="runExample('registration')" class="btn btn-success w-full mb-4">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"></path>
|
||||
</svg>
|
||||
Run Example
|
||||
</button>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header"><span>PHP</span></div>
|
||||
<pre class="!m-0"><code class="language-php">flash()->success('Welcome! Your account has been created.');
|
||||
flash()->info('Please check your email to verify your account.');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# Login Flow #}
|
||||
<div class="card">
|
||||
<div class="h-2 bg-gradient-to-r from-rose-500 to-red-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center space-x-3 mb-4">
|
||||
<div class="p-3 bg-rose-100 rounded-xl">
|
||||
<svg class="w-6 h-6 text-rose-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-lg font-bold text-gray-800">Login Failed</h3>
|
||||
<p class="text-sm text-gray-500">Authentication error</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 mb-4">Shows how to display login failure messages with helpful guidance.</p>
|
||||
|
||||
<button onclick="runExample('login_failed')" class="btn btn-danger w-full mb-4">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"></path>
|
||||
</svg>
|
||||
Run Example
|
||||
</button>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header"><span>PHP</span></div>
|
||||
<pre class="!m-0"><code class="language-php">flash()->error('Invalid email or password.');
|
||||
flash()->info('Forgot your password? Click here to reset.');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# Shopping Cart #}
|
||||
<div class="card">
|
||||
<div class="h-2 bg-gradient-to-r from-indigo-500 to-purple-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center space-x-3 mb-4">
|
||||
<div class="p-3 bg-indigo-100 rounded-xl">
|
||||
<svg class="w-6 h-6 text-indigo-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 3h2l.4 2M7 13h10l4-8H5.4M7 13L5.4 5M7 13l-2.293 2.293c-.63.63-.184 1.707.707 1.707H17m0 0a2 2 0 100 4 2 2 0 000-4zm-8 2a2 2 0 11-4 0 2 2 0 014 0z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-lg font-bold text-gray-800">Shopping Cart</h3>
|
||||
<p class="text-sm text-gray-500">E-commerce interactions</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 mb-4">Shows notifications for adding items to cart with stock warnings and promotions.</p>
|
||||
|
||||
<button onclick="runExample('shopping_cart')" class="btn btn-primary w-full mb-4">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"></path>
|
||||
</svg>
|
||||
Run Example
|
||||
</button>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header"><span>PHP</span></div>
|
||||
<pre class="!m-0"><code class="language-php">flash()->success('iPhone 15 Pro added to cart!');
|
||||
flash()->warning('Only 2 items left in stock!');
|
||||
flash()->info('Add $20 more for free shipping!');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# Payment Success #}
|
||||
<div class="card">
|
||||
<div class="h-2 bg-gradient-to-r from-green-500 to-emerald-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center space-x-3 mb-4">
|
||||
<div class="p-3 bg-green-100 rounded-xl">
|
||||
<svg class="w-6 h-6 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-lg font-bold text-gray-800">Payment Success</h3>
|
||||
<p class="text-sm text-gray-500">Transaction completed</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 mb-4">Payment confirmation with order details and receipt notification.</p>
|
||||
|
||||
<button onclick="runExample('payment_success')" class="btn btn-success w-full mb-4">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"></path>
|
||||
</svg>
|
||||
Run Example
|
||||
</button>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header"><span>PHP</span></div>
|
||||
<pre class="!m-0"><code class="language-php">flash()->success('Payment of $149.99 confirmed!');
|
||||
flash()->info('Order #12345 - Receipt sent to your email.');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# Delete Confirmation #}
|
||||
<div class="card">
|
||||
<div class="h-2 bg-gradient-to-r from-pink-500 to-rose-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center space-x-3 mb-4">
|
||||
<div class="p-3 bg-pink-100 rounded-xl">
|
||||
<svg class="w-6 h-6 text-pink-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-lg font-bold text-gray-800">Delete Confirmation</h3>
|
||||
<p class="text-sm text-gray-500">SweetAlert dialog</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 mb-4">Uses SweetAlert for a confirmation dialog before deleting.</p>
|
||||
|
||||
<button onclick="runExample('delete_confirm')" class="btn btn-danger w-full mb-4">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"></path>
|
||||
</svg>
|
||||
Run Example
|
||||
</button>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header"><span>PHP</span></div>
|
||||
<pre class="!m-0"><code class="language-php">sweetalert()
|
||||
->showCancelButton()
|
||||
->confirmButtonText('Yes, delete it!')
|
||||
->cancelButtonText('Cancel')
|
||||
->warning('Are you sure? This cannot be undone.');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# Settings Saved #}
|
||||
<div class="card">
|
||||
<div class="h-2 bg-gradient-to-r from-teal-500 to-green-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center space-x-3 mb-4">
|
||||
<div class="p-3 bg-teal-100 rounded-xl">
|
||||
<svg class="w-6 h-6 text-teal-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"></path>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-lg font-bold text-gray-800">Settings Saved</h3>
|
||||
<p class="text-sm text-gray-500">Preferences updated</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 mb-4">Shows settings save confirmation with additional context.</p>
|
||||
|
||||
<button onclick="runExample('settings')" class="btn btn-success w-full mb-4">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"></path>
|
||||
</svg>
|
||||
Run Example
|
||||
</button>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header"><span>PHP</span></div>
|
||||
<pre class="!m-0"><code class="language-php">flash()->success('Settings saved successfully!');
|
||||
flash()->info('Some changes may require a page refresh.');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -1,232 +0,0 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block title %}PHPFlasher - Notification Positions{% endblock %}
|
||||
|
||||
{% block page_title %}Notification Positions{% endblock %}
|
||||
{% block page_subtitle %}Control where your notifications appear on the screen{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="bg-white rounded-lg shadow-md overflow-hidden mb-8">
|
||||
<div class="p-6">
|
||||
<h2 class="text-xl font-bold mb-4">Available Positions</h2>
|
||||
<p class="text-gray-600 mb-6">
|
||||
PHPFlasher allows you to position your notifications in different areas of the screen.
|
||||
You can choose from 9 different positions to best fit your design and user experience needs.
|
||||
</p>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-8">
|
||||
<div class="relative h-72 bg-gray-100 rounded-lg overflow-hidden border border-gray-200">
|
||||
<div class="absolute top-2 left-2 bg-indigo-100 text-indigo-800 px-3 py-1 rounded-lg text-sm">top-left</div>
|
||||
<div class="absolute top-2 right-2 bg-white shadow-md p-3 rounded w-3/4">
|
||||
<div class="h-2 w-12 bg-indigo-500 mb-2 rounded"></div>
|
||||
<div class="h-2 w-20 bg-gray-300 mb-2 rounded"></div>
|
||||
<div class="h-2 w-16 bg-gray-300 rounded"></div>
|
||||
</div>
|
||||
<button class="absolute bottom-4 left-1/2 transform -translate-x-1/2 btn btn-primary notification-position" data-position="top-left">
|
||||
Show Notification
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="relative h-72 bg-gray-100 rounded-lg overflow-hidden border border-gray-200">
|
||||
<div class="absolute top-2 left-1/2 transform -translate-x-1/2 bg-indigo-100 text-indigo-800 px-3 py-1 rounded-lg text-sm">top-center</div>
|
||||
<div class="absolute top-2 left-1/2 transform -translate-x-1/2 bg-white shadow-md p-3 rounded w-3/4">
|
||||
<div class="h-2 w-12 bg-indigo-500 mb-2 rounded"></div>
|
||||
<div class="h-2 w-20 bg-gray-300 mb-2 rounded"></div>
|
||||
<div class="h-2 w-16 bg-gray-300 rounded"></div>
|
||||
</div>
|
||||
<button class="absolute bottom-4 left-1/2 transform -translate-x-1/2 btn btn-primary notification-position" data-position="top-center">
|
||||
Show Notification
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="relative h-72 bg-gray-100 rounded-lg overflow-hidden border border-gray-200">
|
||||
<div class="absolute top-2 right-2 bg-indigo-100 text-indigo-800 px-3 py-1 rounded-lg text-sm">top-right</div>
|
||||
<div class="absolute top-2 right-2 bg-white shadow-md p-3 rounded w-3/4">
|
||||
<div class="h-2 w-12 bg-indigo-500 mb-2 rounded"></div>
|
||||
<div class="h-2 w-20 bg-gray-300 mb-2 rounded"></div>
|
||||
<div class="h-2 w-16 bg-gray-300 rounded"></div>
|
||||
</div>
|
||||
<button class="absolute bottom-4 left-1/2 transform -translate-x-1/2 btn btn-primary notification-position" data-position="top-right">
|
||||
Show Notification
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="relative h-72 bg-gray-100 rounded-lg overflow-hidden border border-gray-200">
|
||||
<div class="absolute top-1/2 left-2 transform -translate-y-1/2 bg-indigo-100 text-indigo-800 px-3 py-1 rounded-lg text-sm">center-left</div>
|
||||
<div class="absolute top-1/2 left-2 transform -translate-y-1/2 bg-white shadow-md p-3 rounded w-3/4">
|
||||
<div class="h-2 w-12 bg-indigo-500 mb-2 rounded"></div>
|
||||
<div class="h-2 w-20 bg-gray-300 mb-2 rounded"></div>
|
||||
<div class="h-2 w-16 bg-gray-300 rounded"></div>
|
||||
</div>
|
||||
<button class="absolute bottom-4 left-1/2 transform -translate-x-1/2 btn btn-primary notification-position" data-position="center-left">
|
||||
Show Notification
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="relative h-72 bg-gray-100 rounded-lg overflow-hidden border border-gray-200">
|
||||
<div class="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 bg-indigo-100 text-indigo-800 px-3 py-1 rounded-lg text-sm">center</div>
|
||||
<div class="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 bg-white shadow-md p-3 rounded w-3/4">
|
||||
<div class="h-2 w-12 bg-indigo-500 mb-2 rounded"></div>
|
||||
<div class="h-2 w-20 bg-gray-300 mb-2 rounded"></div>
|
||||
<div class="h-2 w-16 bg-gray-300 rounded"></div>
|
||||
</div>
|
||||
<button class="absolute bottom-4 left-1/2 transform -translate-x-1/2 btn btn-primary notification-position" data-position="center">
|
||||
Show Notification
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="relative h-72 bg-gray-100 rounded-lg overflow-hidden border border-gray-200">
|
||||
<div class="absolute top-1/2 right-2 transform -translate-y-1/2 bg-indigo-100 text-indigo-800 px-3 py-1 rounded-lg text-sm">center-right</div>
|
||||
<div class="absolute top-1/2 right-2 transform -translate-y-1/2 bg-white shadow-md p-3 rounded w-3/4">
|
||||
<div class="h-2 w-12 bg-indigo-500 mb-2 rounded"></div>
|
||||
<div class="h-2 w-20 bg-gray-300 mb-2 rounded"></div>
|
||||
<div class="h-2 w-16 bg-gray-300 rounded"></div>
|
||||
</div>
|
||||
<button class="absolute bottom-4 left-1/2 transform -translate-x-1/2 btn btn-primary notification-position" data-position="center-right">
|
||||
Show Notification
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="relative h-72 bg-gray-100 rounded-lg overflow-hidden border border-gray-200">
|
||||
<div class="absolute bottom-2 left-2 bg-indigo-100 text-indigo-800 px-3 py-1 rounded-lg text-sm">bottom-left</div>
|
||||
<div class="absolute bottom-10 left-2 bg-white shadow-md p-3 rounded w-3/4">
|
||||
<div class="h-2 w-12 bg-indigo-500 mb-2 rounded"></div>
|
||||
<div class="h-2 w-20 bg-gray-300 mb-2 rounded"></div>
|
||||
<div class="h-2 w-16 bg-gray-300 rounded"></div>
|
||||
</div>
|
||||
<button class="absolute bottom-4 left-1/2 transform -translate-x-1/2 btn btn-primary notification-position" data-position="bottom-left">
|
||||
Show Notification
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="relative h-72 bg-gray-100 rounded-lg overflow-hidden border border-gray-200">
|
||||
<div class="absolute bottom-2 left-1/2 transform -translate-x-1/2 bg-indigo-100 text-indigo-800 px-3 py-1 rounded-lg text-sm">bottom-center</div>
|
||||
<div class="absolute bottom-10 left-1/2 transform -translate-x-1/2 bg-white shadow-md p-3 rounded w-3/4">
|
||||
<div class="h-2 w-12 bg-indigo-500 mb-2 rounded"></div>
|
||||
<div class="h-2 w-20 bg-gray-300 mb-2 rounded"></div>
|
||||
<div class="h-2 w-16 bg-gray-300 rounded"></div>
|
||||
</div>
|
||||
<button class="absolute bottom-4 left-1/2 transform -translate-x-1/2 btn btn-primary notification-position" data-position="bottom-center">
|
||||
Show Notification
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="relative h-72 bg-gray-100 rounded-lg overflow-hidden border border-gray-200">
|
||||
<div class="absolute bottom-2 right-2 bg-indigo-100 text-indigo-800 px-3 py-1 rounded-lg text-sm">bottom-right</div>
|
||||
<div class="absolute bottom-10 right-2 bg-white shadow-md p-3 rounded w-3/4">
|
||||
<div class="h-2 w-12 bg-indigo-500 mb-2 rounded"></div>
|
||||
<div class="h-2 w-20 bg-gray-300 mb-2 rounded"></div>
|
||||
<div class="h-2 w-16 bg-gray-300 rounded"></div>
|
||||
</div>
|
||||
<button class="absolute bottom-4 left-1/2 transform -translate-x-1/2 btn btn-primary notification-position" data-position="bottom-right">
|
||||
Show Notification
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-white rounded-lg shadow-md overflow-hidden mb-8">
|
||||
<div class="p-6">
|
||||
<h2 class="text-xl font-bold mb-4">Setting Positions in Code</h2>
|
||||
<p class="text-gray-600 mb-4">
|
||||
You can set the position of notifications in your PHP code using the <code>option()</code> method:
|
||||
</p>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>PHP</span>
|
||||
</div>
|
||||
<pre><code class="language-php">// Top-right position (default)
|
||||
flash()->success('Your changes have been saved.');
|
||||
|
||||
// Bottom-left position
|
||||
flash()->option('position', 'bottom-left')
|
||||
->success('Your changes have been saved.');
|
||||
|
||||
// Top-center position
|
||||
flash()->option('position', 'top-center')
|
||||
->info('You have 3 unread messages.');
|
||||
|
||||
// Center position (middle of the screen)
|
||||
flash()->option('position', 'center')
|
||||
->warning('Your session will expire in 1 minute.');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-white rounded-lg shadow-md overflow-hidden">
|
||||
<div class="p-6">
|
||||
<h2 class="text-xl font-bold mb-4">Global Position Configuration</h2>
|
||||
<p class="text-gray-600 mb-4">
|
||||
You can set a default position for all notifications in your configuration file:
|
||||
</p>
|
||||
|
||||
<div class="code-block mb-6">
|
||||
<div class="code-header">
|
||||
<span>YAML</span>
|
||||
</div>
|
||||
<pre><code class="language-yaml"># config/packages/flasher.yaml
|
||||
flasher:
|
||||
options:
|
||||
position: 'top-right' # Default position for all notifications</code></pre>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 mb-4">
|
||||
Or you can set specific positions for different themes:
|
||||
</p>
|
||||
|
||||
<div class="code-block mb-6">
|
||||
<div class="code-header">
|
||||
<span>YAML</span>
|
||||
</div>
|
||||
<pre><code class="language-yaml"># config/packages/flasher.yaml
|
||||
flasher:
|
||||
themes:
|
||||
amazon:
|
||||
options:
|
||||
position: 'bottom-right'
|
||||
|
||||
sapphire:
|
||||
options:
|
||||
position: 'top-center'</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-center">
|
||||
<a href="{{ path('app_themes') }}" class="btn btn-primary">
|
||||
Explore Themes
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block javascripts %}
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const positionButtons = document.querySelectorAll('.notification-position');
|
||||
|
||||
positionButtons.forEach(button => {
|
||||
button.addEventListener('click', function() {
|
||||
const position = this.getAttribute('data-position');
|
||||
|
||||
// Send AJAX request to show notification
|
||||
fetch('{{ path('app_show_notification') }}', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Requested-With': 'XMLHttpRequest'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
type: 'success',
|
||||
message: 'This notification is at the ' + position + ' position!',
|
||||
options: {
|
||||
position: position
|
||||
}
|
||||
})
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -1,220 +0,0 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block title %}PHPFlasher - Notification Types{% endblock %}
|
||||
|
||||
{% block page_title %}Notification Types{% endblock %}
|
||||
{% block page_subtitle %}Display different notification types to communicate various messages{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="bg-white rounded-lg shadow-md overflow-hidden mb-8">
|
||||
<div class="p-6">
|
||||
<h2 class="text-xl font-bold mb-4">Available Notification Types</h2>
|
||||
<p class="text-gray-600 mb-6">
|
||||
PHPFlasher provides four primary notification types to communicate different types of messages to your users.
|
||||
Each type has a distinct visual style to clearly convey the nature of the message.
|
||||
</p>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-8">
|
||||
<div class="border border-gray-200 rounded-lg p-4 hover:shadow-md transition-shadow">
|
||||
<div class="flex items-center mb-3">
|
||||
<div class="bg-emerald-100 p-2 rounded-md mr-3">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 text-emerald-600" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="text-lg font-semibold">Success</h3>
|
||||
</div>
|
||||
<p class="text-gray-600 mb-3">
|
||||
Used for positive feedback when an action has been completed successfully.
|
||||
</p>
|
||||
<div class="code-block mb-3">
|
||||
<div class="code-header">
|
||||
<span>PHP</span>
|
||||
</div>
|
||||
<pre><code class="language-php">flash()->success('Your profile has been updated successfully!');</code></pre>
|
||||
</div>
|
||||
<button class="btn btn-success w-full notification-demo" data-type="success" data-message="This is a success notification!">
|
||||
Show Success Notification
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="border border-gray-200 rounded-lg p-4 hover:shadow-md transition-shadow">
|
||||
<div class="flex items-center mb-3">
|
||||
<div class="bg-rose-100 p-2 rounded-md mr-3">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 text-rose-600" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="text-lg font-semibold">Error</h3>
|
||||
</div>
|
||||
<p class="text-gray-600 mb-3">
|
||||
Used to alert users about errors or problems that need attention.
|
||||
</p>
|
||||
<div class="code-block mb-3">
|
||||
<div class="code-header">
|
||||
<span>PHP</span>
|
||||
</div>
|
||||
<pre><code class="language-php">flash()->error('An error occurred while processing your request.');</code></pre>
|
||||
</div>
|
||||
<button class="btn btn-danger w-full notification-demo" data-type="error" data-message="This is an error notification!">
|
||||
Show Error Notification
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="border border-gray-200 rounded-lg p-4 hover:shadow-md transition-shadow">
|
||||
<div class="flex items-center mb-3">
|
||||
<div class="bg-amber-100 p-2 rounded-md mr-3">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 text-amber-600" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="text-lg font-semibold">Warning</h3>
|
||||
</div>
|
||||
<p class="text-gray-600 mb-3">
|
||||
Used to inform users about potential issues or actions they should be aware of.
|
||||
</p>
|
||||
<div class="code-block mb-3">
|
||||
<div class="code-header">
|
||||
<span>PHP</span>
|
||||
</div>
|
||||
<pre><code class="language-php">flash()->warning('Your subscription will expire in 3 days.');</code></pre>
|
||||
</div>
|
||||
<button class="btn btn-warning w-full notification-demo" data-type="warning" data-message="This is a warning notification!">
|
||||
Show Warning Notification
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="border border-gray-200 rounded-lg p-4 hover:shadow-md transition-shadow">
|
||||
<div class="flex items-center mb-3">
|
||||
<div class="bg-sky-100 p-2 rounded-md mr-3">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 text-sky-600" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="text-lg font-semibold">Info</h3>
|
||||
</div>
|
||||
<p class="text-gray-600 mb-3">
|
||||
Used to provide neutral information or updates to users.
|
||||
</p>
|
||||
<div class="code-block mb-3">
|
||||
<div class="code-header">
|
||||
<span>PHP</span>
|
||||
</div>
|
||||
<pre><code class="language-php">flash()->info('You have 5 unread messages.');</code></pre>
|
||||
</div>
|
||||
<button class="btn btn-info w-full notification-demo" data-type="info" data-message="This is an info notification!">
|
||||
Show Info Notification
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-white rounded-lg shadow-md overflow-hidden mb-8">
|
||||
<div class="p-6">
|
||||
<h2 class="text-xl font-bold mb-4">Usage in Controllers</h2>
|
||||
<p class="text-gray-600 mb-4">
|
||||
Here's how you can use notification types in your Symfony controllers:
|
||||
</p>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>PHP</span>
|
||||
</div>
|
||||
<pre><code class="language-php"><?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
|
||||
class ExampleController extends AbstractController
|
||||
{
|
||||
#[Route('/process-form', name: 'app_process_form')]
|
||||
public function processForm(): Response
|
||||
{
|
||||
// Simulate form processing
|
||||
$success = true;
|
||||
|
||||
if ($success) {
|
||||
// Show success notification
|
||||
flash()->success('Form submitted successfully!');
|
||||
} else {
|
||||
// Show error notification
|
||||
flash()->error('An error occurred while processing the form.');
|
||||
}
|
||||
|
||||
// Show info notification
|
||||
flash()->info('You will receive a confirmation email shortly.');
|
||||
|
||||
// Show warning notification
|
||||
flash()->warning('Please verify your email within 24 hours.');
|
||||
|
||||
return $this->redirectToRoute('app_home');
|
||||
}
|
||||
}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-white rounded-lg shadow-md overflow-hidden">
|
||||
<div class="p-6">
|
||||
<h2 class="text-xl font-bold mb-4">Advanced Usage</h2>
|
||||
<p class="text-gray-600 mb-4">
|
||||
You can combine notification types with other options to create more customized notifications:
|
||||
</p>
|
||||
|
||||
<div class="code-block mb-6">
|
||||
<div class="code-header">
|
||||
<span>PHP</span>
|
||||
</div>
|
||||
<pre><code class="language-php">// Success notification with custom timeout
|
||||
flash()->option('timeout', 8000)
|
||||
->success('Changes saved successfully!');
|
||||
|
||||
// Warning notification with custom position
|
||||
flash()->option('position', 'bottom-center')
|
||||
->warning('Your session will expire soon.');
|
||||
|
||||
// Error notification with progress bar
|
||||
flash()->option('showProgressbar', true)
|
||||
->error('Unable to connect to the server.');</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-center">
|
||||
<a href="{{ path('app_options') }}" class="btn btn-primary">
|
||||
Learn More About Options
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block javascripts %}
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const demoButtons = document.querySelectorAll('.notification-demo');
|
||||
|
||||
demoButtons.forEach(button => {
|
||||
button.addEventListener('click', function() {
|
||||
const type = this.getAttribute('data-type');
|
||||
const message = this.getAttribute('data-message') || 'This is a notification!';
|
||||
|
||||
// Send AJAX request to show notification
|
||||
fetch('{{ path('app_show_notification') }}', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Requested-With': 'XMLHttpRequest'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
type: type,
|
||||
message: message
|
||||
})
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,197 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block title %}Home{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{# Hero Section #}
|
||||
<div class="text-center mb-12">
|
||||
<h1 class="text-4xl md:text-5xl font-bold text-gray-900 mb-4">
|
||||
Beautiful Flash Notifications
|
||||
</h1>
|
||||
<p class="text-xl text-gray-600 max-w-2xl mx-auto mb-8">
|
||||
PHPFlasher makes it easy to add elegant notifications to your Symfony application.
|
||||
Try the quick demos below!
|
||||
</p>
|
||||
|
||||
{# Quick Demo Buttons #}
|
||||
<div class="flex flex-wrap justify-center gap-3 mb-8">
|
||||
<button onclick="showNotification({type: 'success', message: 'Operation completed successfully!', title: 'Success'})"
|
||||
class="btn btn-success">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
|
||||
</svg>
|
||||
Success
|
||||
</button>
|
||||
<button onclick="showNotification({type: 'error', message: 'Something went wrong. Please try again.', title: 'Error'})"
|
||||
class="btn btn-danger">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
|
||||
</svg>
|
||||
Error
|
||||
</button>
|
||||
<button onclick="showNotification({type: 'warning', message: 'Please review your input before continuing.', title: 'Warning'})"
|
||||
class="btn btn-warning">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"></path>
|
||||
</svg>
|
||||
Warning
|
||||
</button>
|
||||
<button onclick="showNotification({type: 'info', message: 'Here is some useful information for you.', title: 'Info'})"
|
||||
class="btn btn-info">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
Info
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# Features Grid #}
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 mb-12">
|
||||
{# Feature 1: Types #}
|
||||
<a href="{{ path('app_types') }}" class="card group">
|
||||
<div class="h-2 bg-gradient-to-r from-emerald-500 to-teal-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center space-x-3 mb-3">
|
||||
<div class="p-2 bg-emerald-100 rounded-lg group-hover:bg-emerald-200 transition-colors">
|
||||
<svg class="w-6 h-6 text-emerald-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 8h10M7 12h4m1 8l-4-4H5a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v8a2 2 0 01-2 2h-3l-4 4z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="text-xl font-bold text-gray-800">Notification Types</h3>
|
||||
</div>
|
||||
<p class="text-gray-600">Success, error, warning, and info notifications for every use case.</p>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
{# Feature 2: Themes #}
|
||||
<a href="{{ path('app_themes') }}" class="card group">
|
||||
<div class="h-2 bg-gradient-to-r from-purple-500 to-pink-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center space-x-3 mb-3">
|
||||
<div class="p-2 bg-purple-100 rounded-lg group-hover:bg-purple-200 transition-colors">
|
||||
<svg class="w-6 h-6 text-purple-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 21a4 4 0 01-4-4V5a2 2 0 012-2h4a2 2 0 012 2v12a4 4 0 01-4 4zm0 0h12a2 2 0 002-2v-4a2 2 0 00-2-2h-2.343M11 7.343l1.657-1.657a2 2 0 012.828 0l2.829 2.829a2 2 0 010 2.828l-8.486 8.485M7 17h.01"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="text-xl font-bold text-gray-800">17+ Themes</h3>
|
||||
</div>
|
||||
<p class="text-gray-600">Material, iOS, Slack, Amazon, and many more beautiful themes.</p>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
{# Feature 3: Adapters #}
|
||||
<a href="{{ path('app_adapters') }}" class="card group">
|
||||
<div class="h-2 bg-gradient-to-r from-blue-500 to-cyan-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center space-x-3 mb-3">
|
||||
<div class="p-2 bg-blue-100 rounded-lg group-hover:bg-blue-200 transition-colors">
|
||||
<svg class="w-6 h-6 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 14v6m-3-3h6M6 10h2a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v2a2 2 0 002 2zm10 0h2a2 2 0 002-2V6a2 2 0 00-2-2h-2a2 2 0 00-2 2v2a2 2 0 002 2zM6 20h2a2 2 0 002-2v-2a2 2 0 00-2-2H6a2 2 0 00-2 2v2a2 2 0 002 2z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="text-xl font-bold text-gray-800">Multiple Adapters</h3>
|
||||
</div>
|
||||
<p class="text-gray-600">Toastr, SweetAlert, Noty, and Notyf adapters included.</p>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
{# Feature 4: Positions #}
|
||||
<a href="{{ path('app_positions') }}" class="card group">
|
||||
<div class="h-2 bg-gradient-to-r from-amber-500 to-orange-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center space-x-3 mb-3">
|
||||
<div class="p-2 bg-amber-100 rounded-lg group-hover:bg-amber-200 transition-colors">
|
||||
<svg class="w-6 h-6 text-amber-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 5a1 1 0 011-1h14a1 1 0 011 1v2a1 1 0 01-1 1H5a1 1 0 01-1-1V5zM4 13a1 1 0 011-1h6a1 1 0 011 1v6a1 1 0 01-1 1H5a1 1 0 01-1-1v-6zM16 13a1 1 0 011-1h2a1 1 0 011 1v6a1 1 0 01-1 1h-2a1 1 0 01-1-1v-6z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="text-xl font-bold text-gray-800">Flexible Positions</h3>
|
||||
</div>
|
||||
<p class="text-gray-600">Place notifications anywhere on the screen.</p>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
{# Feature 5: Examples #}
|
||||
<a href="{{ path('app_examples') }}" class="card group">
|
||||
<div class="h-2 bg-gradient-to-r from-rose-500 to-red-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center space-x-3 mb-3">
|
||||
<div class="p-2 bg-rose-100 rounded-lg group-hover:bg-rose-200 transition-colors">
|
||||
<svg class="w-6 h-6 text-rose-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="text-xl font-bold text-gray-800">Real Examples</h3>
|
||||
</div>
|
||||
<p class="text-gray-600">User registration, shopping cart, payments, and more.</p>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
{# Feature 6: Playground #}
|
||||
<a href="{{ path('app_playground') }}" class="card group">
|
||||
<div class="h-2 bg-gradient-to-r from-indigo-500 to-violet-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center space-x-3 mb-3">
|
||||
<div class="p-2 bg-indigo-100 rounded-lg group-hover:bg-indigo-200 transition-colors">
|
||||
<svg class="w-6 h-6 text-indigo-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"></path>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="text-xl font-bold text-gray-800">Interactive Playground</h3>
|
||||
</div>
|
||||
<p class="text-gray-600">Build and customize notifications in real-time.</p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{# Quick Start Code #}
|
||||
<div class="card mb-12">
|
||||
<div class="card-header">
|
||||
<h2 class="text-xl font-bold text-gray-800">Quick Start</h2>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p class="text-gray-600 mb-4">Get started with PHPFlasher in seconds. Just install and use!</p>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>Installation</span>
|
||||
</div>
|
||||
<pre class="!m-0"><code class="language-bash">composer require php-flasher/flasher-symfony</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>Usage</span>
|
||||
</div>
|
||||
<pre class="!m-0"><code class="language-php">// In your controller
|
||||
flash()->success('Profile updated successfully!');
|
||||
|
||||
// With options
|
||||
flash()->success('Welcome back!', [
|
||||
'position' => 'top-right',
|
||||
'timeout' => 5000,
|
||||
]);
|
||||
|
||||
// Using themes
|
||||
flash()->use('theme.material')->info('New feature available!');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# CTA Section #}
|
||||
<div class="bg-gradient-to-r from-indigo-600 to-purple-600 rounded-2xl p-8 text-center text-white">
|
||||
<h2 class="text-2xl md:text-3xl font-bold mb-4">Ready to try PHPFlasher?</h2>
|
||||
<p class="text-indigo-100 mb-6 max-w-xl mx-auto">
|
||||
Explore the interactive playground to customize notifications and see the generated code.
|
||||
</p>
|
||||
<a href="{{ path('app_playground') }}" class="inline-flex items-center px-6 py-3 bg-white text-indigo-600 font-semibold rounded-lg hover:bg-indigo-50 transition-colors">
|
||||
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"></path>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
Open Playground
|
||||
</a>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -1,97 +0,0 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block title %}PHPFlasher Features{% endblock %}
|
||||
|
||||
{% block page_title %}PHPFlasher Features{% endblock %}
|
||||
{% block page_subtitle %}Explore the powerful features of PHPFlasher{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 mb-12">
|
||||
<div class="bg-white rounded-lg shadow-md overflow-hidden hover:shadow-lg transition duration-300">
|
||||
<div class="bg-indigo-600 h-2"></div>
|
||||
<div class="p-6">
|
||||
<div class="flex items-center space-x-3 mb-3">
|
||||
<div class="bg-indigo-100 p-2 rounded-md">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 text-indigo-600" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 8h10M7 12h4m1 8l-4-4H5a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v8a2 2 0 01-2 2h-3l-4 4z" />
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="text-xl font-bold text-gray-800">Notification Types</h3>
|
||||
</div>
|
||||
<p class="text-gray-600">Display success, error, warning, and info notifications to communicate different messages to your users.</p>
|
||||
<div class="mt-4">
|
||||
<a href="{{ path('app_types') }}" class="text-indigo-600 hover:text-indigo-800 font-medium">See Notification Types →</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-white rounded-lg shadow-md overflow-hidden hover:shadow-lg transition duration-300">
|
||||
<div class="bg-emerald-600 h-2"></div>
|
||||
<div class="p-6">
|
||||
<div class="flex items-center space-x-3 mb-3">
|
||||
<div class="bg-emerald-100 p-2 rounded-md">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 text-emerald-600" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 20l-5.447-2.724A1 1 0 013 16.382V5.618a1 1 0 011.447-.894L9 7m0 13l6-3m-6 3V7m6 10l4.553 2.276A1 1 0 0021 18.382V7.618a1 1 0 00-.553-.894L15 4m0 13V4" />
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="text-xl font-bold text-gray-800">Notification Positions</h3>
|
||||
</div>
|
||||
<p class="text-gray-600">Place notifications in different positions around the screen to best suit your UI design.</p>
|
||||
<div class="mt-4">
|
||||
<a href="{{ path('app_positions') }}" class="text-emerald-600 hover:text-emerald-800 font-medium">Explore Positions →</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-white rounded-lg shadow-md overflow-hidden hover:shadow-lg transition duration-300">
|
||||
<div class="bg-amber-500 h-2"></div>
|
||||
<div class="p-6">
|
||||
<div class="flex items-center space-x-3 mb-3">
|
||||
<div class="bg-amber-100 p-2 rounded-md">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 text-amber-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" />
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="text-xl font-bold text-gray-800">Configuration Options</h3>
|
||||
</div>
|
||||
<p class="text-gray-600">Customize timeouts, animations, progressbars, and more with PHPFlasher's flexible configuration.</p>
|
||||
<div class="mt-4">
|
||||
<a href="{{ path('app_options') }}" class="text-amber-600 hover:text-amber-800 font-medium">View Options →</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-8 mb-12">
|
||||
<div class="bg-white rounded-lg shadow-md overflow-hidden">
|
||||
<div class="p-6">
|
||||
<h3 class="text-xl font-bold mb-4 text-gray-800">Plugins & Extensions</h3>
|
||||
<p class="text-gray-600 mb-4">PHPFlasher can be extended with plugins to add more functionality.</p>
|
||||
<div class="flex justify-end">
|
||||
<a href="{{ path('app_plugins') }}" class="btn btn-primary">Explore Plugins</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-white rounded-lg shadow-md overflow-hidden">
|
||||
<div class="p-6">
|
||||
<h3 class="text-xl font-bold mb-4 text-gray-800">Notification Presets</h3>
|
||||
<p class="text-gray-600 mb-4">Create reusable notification configurations for consistent messaging.</p>
|
||||
<div class="flex justify-end">
|
||||
<a href="{{ path('app_presets') }}" class="btn btn-primary">View Presets</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-indigo-50 rounded-lg p-8 mb-12">
|
||||
<div class="text-center">
|
||||
<h2 class="text-2xl font-bold text-indigo-800 mb-4">Try Out the Interactive Playground</h2>
|
||||
<p class="text-indigo-600 mb-6 max-w-2xl mx-auto">Want to experiment with different notification settings? Use our interactive playground to test PHPFlasher's features in real-time.</p>
|
||||
<div class="flex justify-center">
|
||||
<a href="{{ path('app_playground') }}" class="btn btn-primary">Go to Playground</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,266 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block title %}Playground{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="mb-8">
|
||||
<h1 class="section-title">Interactive Playground</h1>
|
||||
<p class="section-subtitle">Build and customize notifications in real-time. See the generated PHP code instantly.</p>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-8">
|
||||
{# Configuration Panel #}
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h2 class="text-xl font-bold text-gray-800">Configuration</h2>
|
||||
</div>
|
||||
<div class="card-body space-y-6">
|
||||
{# Type #}
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">Notification Type</label>
|
||||
<div class="grid grid-cols-4 gap-2">
|
||||
<button onclick="setType('success')" id="type-success" class="type-btn px-3 py-2 rounded-lg border-2 border-emerald-500 bg-emerald-50 text-emerald-700 font-medium text-sm">
|
||||
Success
|
||||
</button>
|
||||
<button onclick="setType('error')" id="type-error" class="type-btn px-3 py-2 rounded-lg border-2 border-gray-200 bg-white text-gray-600 font-medium text-sm hover:border-rose-500 hover:bg-rose-50 hover:text-rose-700">
|
||||
Error
|
||||
</button>
|
||||
<button onclick="setType('warning')" id="type-warning" class="type-btn px-3 py-2 rounded-lg border-2 border-gray-200 bg-white text-gray-600 font-medium text-sm hover:border-amber-500 hover:bg-amber-50 hover:text-amber-700">
|
||||
Warning
|
||||
</button>
|
||||
<button onclick="setType('info')" id="type-info" class="type-btn px-3 py-2 rounded-lg border-2 border-gray-200 bg-white text-gray-600 font-medium text-sm hover:border-sky-500 hover:bg-sky-50 hover:text-sky-700">
|
||||
Info
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# Title #}
|
||||
<div>
|
||||
<label for="title" class="block text-sm font-medium text-gray-700 mb-2">Title (optional)</label>
|
||||
<input type="text" id="title" placeholder="Enter a title..."
|
||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"
|
||||
oninput="updateCode()">
|
||||
</div>
|
||||
|
||||
{# Message #}
|
||||
<div>
|
||||
<label for="message" class="block text-sm font-medium text-gray-700 mb-2">Message</label>
|
||||
<textarea id="message" rows="2" placeholder="Enter your notification message..."
|
||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"
|
||||
oninput="updateCode()">Operation completed successfully!</textarea>
|
||||
</div>
|
||||
|
||||
{# Position #}
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">Position</label>
|
||||
<select id="position" onchange="updateCode()"
|
||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500">
|
||||
<option value="top-right" selected>Top Right (default)</option>
|
||||
<option value="top-left">Top Left</option>
|
||||
<option value="top-center">Top Center</option>
|
||||
<option value="bottom-right">Bottom Right</option>
|
||||
<option value="bottom-left">Bottom Left</option>
|
||||
<option value="bottom-center">Bottom Center</option>
|
||||
<option value="center">Center</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
{# Theme #}
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">Theme</label>
|
||||
<select id="theme" onchange="updateCode()"
|
||||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500">
|
||||
<option value="">Default (Flasher)</option>
|
||||
<option value="flasher">Flasher</option>
|
||||
<option value="material">Material</option>
|
||||
<option value="ios">iOS</option>
|
||||
<option value="slack">Slack</option>
|
||||
<option value="amazon">Amazon</option>
|
||||
<option value="google">Google</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
{# Timeout #}
|
||||
<div>
|
||||
<label for="timeout" class="block text-sm font-medium text-gray-700 mb-2">
|
||||
Timeout: <span id="timeout-value">5000</span>ms
|
||||
</label>
|
||||
<input type="range" id="timeout" min="1000" max="10000" step="500" value="5000"
|
||||
class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer"
|
||||
oninput="document.getElementById('timeout-value').textContent = this.value; updateCode()">
|
||||
</div>
|
||||
|
||||
{# Show Button #}
|
||||
<button onclick="showPlaygroundNotification()" class="btn btn-primary w-full">
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"></path>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
Show Notification
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# Code Preview #}
|
||||
<div class="space-y-6">
|
||||
<div class="card">
|
||||
<div class="card-header flex justify-between items-center">
|
||||
<h2 class="text-xl font-bold text-gray-800">Generated Code</h2>
|
||||
<button onclick="copyCode()" class="btn btn-sm btn-outline">
|
||||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"></path>
|
||||
</svg>
|
||||
Copy
|
||||
</button>
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
<div class="code-block !my-0 !rounded-none">
|
||||
<div class="code-header">
|
||||
<span>PHP</span>
|
||||
</div>
|
||||
<pre class="!m-0"><code class="language-php" id="generated-code">flash()->success('Operation completed successfully!');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# Preview Card #}
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h2 class="text-xl font-bold text-gray-800">Preview</h2>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="bg-gray-100 rounded-lg p-6 min-h-[200px] flex items-center justify-center">
|
||||
<div id="preview-notification" class="max-w-sm w-full">
|
||||
<div class="bg-emerald-500 text-white p-4 rounded-lg shadow-lg">
|
||||
<div class="flex items-start space-x-3">
|
||||
<svg class="w-6 h-6 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
<div>
|
||||
<p id="preview-title" class="font-semibold hidden"></p>
|
||||
<p id="preview-message" class="text-sm opacity-90">Operation completed successfully!</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-sm text-gray-500 mt-3 text-center">This is a static preview. Click "Show Notification" to see the real notification.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block javascripts %}
|
||||
<script>
|
||||
let currentType = 'success';
|
||||
const typeColors = {
|
||||
success: { border: 'border-emerald-500', bg: 'bg-emerald-50', text: 'text-emerald-700', preview: 'bg-emerald-500' },
|
||||
error: { border: 'border-rose-500', bg: 'bg-rose-50', text: 'text-rose-700', preview: 'bg-rose-500' },
|
||||
warning: { border: 'border-amber-500', bg: 'bg-amber-50', text: 'text-amber-700', preview: 'bg-amber-500' },
|
||||
info: { border: 'border-sky-500', bg: 'bg-sky-50', text: 'text-sky-700', preview: 'bg-sky-500' }
|
||||
};
|
||||
|
||||
function setType(type) {
|
||||
currentType = type;
|
||||
|
||||
document.querySelectorAll('.type-btn').forEach(btn => {
|
||||
btn.className = 'type-btn px-3 py-2 rounded-lg border-2 border-gray-200 bg-white text-gray-600 font-medium text-sm';
|
||||
});
|
||||
|
||||
const activeBtn = document.getElementById(`type-${type}`);
|
||||
const colors = typeColors[type];
|
||||
activeBtn.className = `type-btn px-3 py-2 rounded-lg border-2 ${colors.border} ${colors.bg} ${colors.text} font-medium text-sm`;
|
||||
|
||||
updatePreview();
|
||||
updateCode();
|
||||
}
|
||||
|
||||
function updatePreview() {
|
||||
const previewDiv = document.querySelector('#preview-notification > div');
|
||||
const colors = typeColors[currentType];
|
||||
previewDiv.className = `${colors.preview} text-white p-4 rounded-lg shadow-lg`;
|
||||
|
||||
const title = document.getElementById('title').value;
|
||||
const message = document.getElementById('message').value;
|
||||
|
||||
document.getElementById('preview-title').textContent = title;
|
||||
document.getElementById('preview-title').classList.toggle('hidden', !title);
|
||||
document.getElementById('preview-message').textContent = message || 'Your notification message...';
|
||||
}
|
||||
|
||||
function updateCode() {
|
||||
const type = currentType;
|
||||
const title = document.getElementById('title').value;
|
||||
const message = document.getElementById('message').value || 'Your message here';
|
||||
const position = document.getElementById('position').value;
|
||||
const theme = document.getElementById('theme').value;
|
||||
const timeout = document.getElementById('timeout').value;
|
||||
|
||||
let code = '';
|
||||
const hasOptions = position !== 'top-right' || timeout !== '5000';
|
||||
|
||||
if (theme) {
|
||||
code = `flash()->use('theme.${theme}')`;
|
||||
} else {
|
||||
code = 'flash()';
|
||||
}
|
||||
|
||||
if (hasOptions) {
|
||||
const options = [];
|
||||
if (position !== 'top-right') {
|
||||
options.push(`'position' => '${position}'`);
|
||||
}
|
||||
if (timeout !== '5000') {
|
||||
options.push(`'timeout' => ${timeout}`);
|
||||
}
|
||||
|
||||
if (title) {
|
||||
code += `\n ->${type}('${message}', '${title}', [${options.join(', ')}]);`;
|
||||
} else {
|
||||
code += `\n ->${type}('${message}', [${options.join(', ')}]);`;
|
||||
}
|
||||
} else {
|
||||
if (title) {
|
||||
code += `->${type}('${message}', '${title}');`;
|
||||
} else {
|
||||
code += `->${type}('${message}');`;
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById('generated-code').textContent = code;
|
||||
Prism.highlightElement(document.getElementById('generated-code'));
|
||||
|
||||
updatePreview();
|
||||
}
|
||||
|
||||
function showPlaygroundNotification() {
|
||||
const options = {
|
||||
type: currentType,
|
||||
message: document.getElementById('message').value || 'Your message here',
|
||||
title: document.getElementById('title').value || undefined,
|
||||
position: document.getElementById('position').value,
|
||||
theme: document.getElementById('theme').value || undefined,
|
||||
timeout: parseInt(document.getElementById('timeout').value)
|
||||
};
|
||||
|
||||
showNotification(options);
|
||||
}
|
||||
|
||||
function copyCode() {
|
||||
const code = document.getElementById('generated-code').textContent;
|
||||
navigator.clipboard.writeText(code).then(() => {
|
||||
const btn = event.target.closest('button');
|
||||
const originalText = btn.innerHTML;
|
||||
btn.innerHTML = '<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path></svg> Copied!';
|
||||
setTimeout(() => {
|
||||
btn.innerHTML = originalText;
|
||||
}, 2000);
|
||||
});
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
updateCode();
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,147 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block title %}Positions{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="mb-8">
|
||||
<h1 class="section-title">Notification Positions</h1>
|
||||
<p class="section-subtitle">Place your notifications anywhere on the screen. Click any position to see it in action.</p>
|
||||
</div>
|
||||
|
||||
{# Interactive Position Grid #}
|
||||
<div class="card mb-8">
|
||||
<div class="card-header">
|
||||
<h2 class="text-xl font-bold text-gray-800">Click a Position</h2>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="bg-gray-100 rounded-xl p-4 relative" style="min-height: 400px;">
|
||||
{# Visual Browser Frame #}
|
||||
<div class="bg-white rounded-lg shadow-lg overflow-hidden h-full" style="min-height: 380px;">
|
||||
{# Browser Header #}
|
||||
<div class="bg-gray-200 px-4 py-2 flex items-center space-x-2">
|
||||
<div class="w-3 h-3 bg-red-400 rounded-full"></div>
|
||||
<div class="w-3 h-3 bg-yellow-400 rounded-full"></div>
|
||||
<div class="w-3 h-3 bg-green-400 rounded-full"></div>
|
||||
<div class="flex-1 ml-4">
|
||||
<div class="bg-white rounded px-3 py-1 text-sm text-gray-500 max-w-md">your-app.com</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# Position Grid #}
|
||||
<div class="grid grid-cols-3 grid-rows-3 gap-2 p-4" style="min-height: 340px;">
|
||||
{# Top Left #}
|
||||
<button onclick="showNotification({type: 'info', message: 'Top Left notification', position: 'top-left'})"
|
||||
class="flex items-start justify-start p-4 bg-indigo-50 hover:bg-indigo-100 rounded-lg transition-colors group">
|
||||
<div class="bg-indigo-500 text-white px-3 py-2 rounded-lg text-sm font-medium group-hover:scale-105 transition-transform">
|
||||
top-left
|
||||
</div>
|
||||
</button>
|
||||
|
||||
{# Top Center #}
|
||||
<button onclick="showNotification({type: 'info', message: 'Top Center notification', position: 'top-center'})"
|
||||
class="flex items-start justify-center p-4 bg-purple-50 hover:bg-purple-100 rounded-lg transition-colors group">
|
||||
<div class="bg-purple-500 text-white px-3 py-2 rounded-lg text-sm font-medium group-hover:scale-105 transition-transform">
|
||||
top-center
|
||||
</div>
|
||||
</button>
|
||||
|
||||
{# Top Right #}
|
||||
<button onclick="showNotification({type: 'info', message: 'Top Right notification', position: 'top-right'})"
|
||||
class="flex items-start justify-end p-4 bg-pink-50 hover:bg-pink-100 rounded-lg transition-colors group">
|
||||
<div class="bg-pink-500 text-white px-3 py-2 rounded-lg text-sm font-medium group-hover:scale-105 transition-transform">
|
||||
top-right
|
||||
</div>
|
||||
</button>
|
||||
|
||||
{# Center Left #}
|
||||
<button onclick="showNotification({type: 'info', message: 'Center Left notification', position: 'center-left'})"
|
||||
class="flex items-center justify-start p-4 bg-sky-50 hover:bg-sky-100 rounded-lg transition-colors group">
|
||||
<div class="bg-sky-500 text-white px-3 py-2 rounded-lg text-sm font-medium group-hover:scale-105 transition-transform">
|
||||
center-left
|
||||
</div>
|
||||
</button>
|
||||
|
||||
{# Center #}
|
||||
<button onclick="showNotification({type: 'info', message: 'Center notification', position: 'center'})"
|
||||
class="flex items-center justify-center p-4 bg-amber-50 hover:bg-amber-100 rounded-lg transition-colors group">
|
||||
<div class="bg-amber-500 text-white px-3 py-2 rounded-lg text-sm font-medium group-hover:scale-105 transition-transform">
|
||||
center
|
||||
</div>
|
||||
</button>
|
||||
|
||||
{# Center Right #}
|
||||
<button onclick="showNotification({type: 'info', message: 'Center Right notification', position: 'center-right'})"
|
||||
class="flex items-center justify-end p-4 bg-emerald-50 hover:bg-emerald-100 rounded-lg transition-colors group">
|
||||
<div class="bg-emerald-500 text-white px-3 py-2 rounded-lg text-sm font-medium group-hover:scale-105 transition-transform">
|
||||
center-right
|
||||
</div>
|
||||
</button>
|
||||
|
||||
{# Bottom Left #}
|
||||
<button onclick="showNotification({type: 'info', message: 'Bottom Left notification', position: 'bottom-left'})"
|
||||
class="flex items-end justify-start p-4 bg-rose-50 hover:bg-rose-100 rounded-lg transition-colors group">
|
||||
<div class="bg-rose-500 text-white px-3 py-2 rounded-lg text-sm font-medium group-hover:scale-105 transition-transform">
|
||||
bottom-left
|
||||
</div>
|
||||
</button>
|
||||
|
||||
{# Bottom Center #}
|
||||
<button onclick="showNotification({type: 'info', message: 'Bottom Center notification', position: 'bottom-center'})"
|
||||
class="flex items-end justify-center p-4 bg-teal-50 hover:bg-teal-100 rounded-lg transition-colors group">
|
||||
<div class="bg-teal-500 text-white px-3 py-2 rounded-lg text-sm font-medium group-hover:scale-105 transition-transform">
|
||||
bottom-center
|
||||
</div>
|
||||
</button>
|
||||
|
||||
{# Bottom Right #}
|
||||
<button onclick="showNotification({type: 'info', message: 'Bottom Right notification', position: 'bottom-right'})"
|
||||
class="flex items-end justify-end p-4 bg-orange-50 hover:bg-orange-100 rounded-lg transition-colors group">
|
||||
<div class="bg-orange-500 text-white px-3 py-2 rounded-lg text-sm font-medium group-hover:scale-105 transition-transform">
|
||||
bottom-right
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# Code Examples #}
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="text-lg font-bold text-gray-800">Inline Position</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p class="text-gray-600 mb-4">Set the position directly when creating a notification.</p>
|
||||
<div class="code-block">
|
||||
<div class="code-header"><span>PHP</span></div>
|
||||
<pre class="!m-0"><code class="language-php">flash()
|
||||
->option('position', 'top-left')
|
||||
->success('Profile updated!');
|
||||
|
||||
// Or use the fluent method
|
||||
flash()
|
||||
->position('bottom-right')
|
||||
->info('New message received!');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3 class="text-lg font-bold text-gray-800">Global Configuration</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p class="text-gray-600 mb-4">Set a default position for all notifications in your config file.</p>
|
||||
<div class="code-block">
|
||||
<div class="code-header"><span>config/packages/flasher.yaml</span></div>
|
||||
<pre class="!m-0"><code class="language-yaml">flasher:
|
||||
default: flasher
|
||||
options:
|
||||
position: bottom-right</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,72 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block title %}Themes{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="mb-8">
|
||||
<h1 class="section-title">Theme Gallery</h1>
|
||||
<p class="section-subtitle">Choose from 17+ beautiful themes to match your application's design.</p>
|
||||
</div>
|
||||
|
||||
{# Theme Grid #}
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4 mb-12">
|
||||
{% set themes = [
|
||||
{name: 'flasher', label: 'Flasher', desc: 'Default theme', gradient: 'from-indigo-500 to-indigo-600'},
|
||||
{name: 'material', label: 'Material', desc: 'Google Material', gradient: 'from-blue-500 to-blue-600'},
|
||||
{name: 'ios', label: 'iOS', desc: 'Apple style', gradient: 'from-slate-600 to-slate-700'},
|
||||
{name: 'slack', label: 'Slack', desc: 'Slack messaging', gradient: 'from-purple-500 to-purple-600'},
|
||||
{name: 'amazon', label: 'Amazon', desc: 'Amazon alerts', gradient: 'from-orange-500 to-orange-600'},
|
||||
{name: 'google', label: 'Google', desc: 'Google notifications', gradient: 'from-red-500 to-yellow-500'},
|
||||
{name: 'facebook', label: 'Facebook', desc: 'Facebook style', gradient: 'from-blue-600 to-blue-700'},
|
||||
{name: 'minimal', label: 'Minimal', desc: 'Ultra clean', gradient: 'from-gray-400 to-gray-500'},
|
||||
{name: 'neon', label: 'Neon', desc: 'Bright & bold', gradient: 'from-pink-500 to-rose-500'},
|
||||
{name: 'emerald', label: 'Emerald', desc: 'Green palette', gradient: 'from-emerald-500 to-green-600'},
|
||||
{name: 'sapphire', label: 'Sapphire', desc: 'Blue elegance', gradient: 'from-blue-500 to-indigo-600'},
|
||||
{name: 'ruby', label: 'Ruby', desc: 'Red accents', gradient: 'from-red-500 to-rose-600'},
|
||||
{name: 'amber', label: 'Amber', desc: 'Warm tones', gradient: 'from-amber-400 to-orange-500'},
|
||||
{name: 'jade', label: 'Jade', desc: 'Soft green', gradient: 'from-teal-500 to-green-600'},
|
||||
{name: 'onyx', label: 'Onyx', desc: 'Dark mode', gradient: 'from-slate-700 to-slate-900'},
|
||||
{name: 'crystal', label: 'Crystal', desc: 'Transparent', gradient: 'from-cyan-400 to-blue-500'},
|
||||
{name: 'aurora', label: 'Aurora', desc: 'Gradient effects', gradient: 'from-green-400 via-blue-500 to-purple-500'}
|
||||
] %}
|
||||
|
||||
{% for theme in themes %}
|
||||
<div class="card group cursor-pointer" onclick="showNotification({type: 'success', message: 'This is the {{ theme.label }} theme!', title: '{{ theme.label }} Theme', theme: '{{ theme.name }}'})">
|
||||
<div class="h-20 bg-gradient-to-br {{ theme.gradient }} flex items-center justify-center">
|
||||
<span class="text-white text-2xl font-bold">{{ theme.label|slice(0, 1) }}</span>
|
||||
</div>
|
||||
<div class="p-4">
|
||||
<h3 class="font-semibold text-gray-800">{{ theme.label }}</h3>
|
||||
<p class="text-sm text-gray-500">{{ theme.desc }}</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
{# Usage Example #}
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h2 class="text-xl font-bold text-gray-800">Using Themes</h2>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p class="text-gray-600 mb-4">Apply themes to your notifications with the <code class="bg-gray-100 px-2 py-1 rounded">use()</code> method.</p>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>PHP</span>
|
||||
</div>
|
||||
<pre class="!m-0"><code class="language-php">// Use a specific theme
|
||||
flash()->use('theme.material')->success('Material design notification!');
|
||||
|
||||
// Different themes for different messages
|
||||
flash()->use('theme.ios')->info('iOS style notification');
|
||||
flash()->use('theme.slack')->warning('Slack style warning');
|
||||
flash()->use('theme.amazon')->success('Amazon style success');
|
||||
|
||||
// Set default theme in config/packages/flasher.yaml
|
||||
flasher:
|
||||
default: theme.material</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -1,302 +0,0 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block title %}PHPFlasher - Themes{% endblock %}
|
||||
|
||||
{% block page_title %}PHPFlasher Themes{% endblock %}
|
||||
{% block page_subtitle %}Beautiful notification themes to match your application's design{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="bg-white rounded-lg shadow-md overflow-hidden mb-8">
|
||||
<div class="p-6">
|
||||
<h2 class="text-xl font-bold mb-4">Available Themes</h2>
|
||||
<p class="text-gray-600 mb-6">
|
||||
PHPFlasher comes with various themes to help you match the notification style to your application's design.
|
||||
Each theme provides a distinct visual appearance while maintaining the same functionality.
|
||||
</p>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 mb-8">
|
||||
<div class="theme-card">
|
||||
<div class="bg-indigo-600 h-2"></div>
|
||||
<div class="theme-preview bg-indigo-50 flex items-center justify-center p-4">
|
||||
<div class="w-full bg-white rounded-lg shadow-md p-4">
|
||||
<div class="flex">
|
||||
<div class="flex-shrink-0">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-indigo-500" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
</div>
|
||||
<div class="ml-3">
|
||||
<p class="text-sm font-medium text-gray-900">Flasher Default Theme</p>
|
||||
<p class="text-xs text-gray-500">Clean and minimal design</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-4">
|
||||
<h3 class="text-lg font-semibold mb-2">Flasher (Default)</h3>
|
||||
<p class="text-gray-600 text-sm mb-4">The default theme with a clean, minimal design that works well in most applications.</p>
|
||||
<button class="w-full btn btn-primary theme-demo" data-theme="flasher">
|
||||
Preview Theme
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="theme-card">
|
||||
<div class="bg-emerald-600 h-2"></div>
|
||||
<div class="theme-preview bg-emerald-50 flex items-center justify-center p-4">
|
||||
<div class="w-full bg-white rounded-lg shadow-md p-4 border-l-4 border-emerald-500">
|
||||
<div class="flex">
|
||||
<div class="ml-3">
|
||||
<p class="text-sm font-medium text-gray-900">Emerald Theme</p>
|
||||
<p class="text-xs text-gray-500">Elegant left-border style</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-4">
|
||||
<h3 class="text-lg font-semibold mb-2">Emerald</h3>
|
||||
<p class="text-gray-600 text-sm mb-4">A sleek theme with colored left borders and subtle design elements.</p>
|
||||
<button class="w-full btn btn-primary theme-demo" data-theme="emerald">
|
||||
Preview Theme
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="theme-card">
|
||||
<div class="bg-blue-600 h-2"></div>
|
||||
<div class="theme-preview bg-blue-50 flex items-center justify-center p-4">
|
||||
<div class="w-full bg-white rounded-lg shadow-md p-4">
|
||||
<div class="flex">
|
||||
<div class="flex-shrink-0 bg-blue-100 rounded-full p-1">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-blue-500" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2h-1V9a1 1 0 00-1-1z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
</div>
|
||||
<div class="ml-3">
|
||||
<p class="text-sm font-medium text-gray-900">Sapphire Theme</p>
|
||||
<p class="text-xs text-gray-500">Modern with rounded icons</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-4">
|
||||
<h3 class="text-lg font-semibold mb-2">Sapphire</h3>
|
||||
<p class="text-gray-600 text-sm mb-4">A modern theme with rounded icons and smooth animations.</p>
|
||||
<button class="w-full btn btn-primary theme-demo" data-theme="sapphire">
|
||||
Preview Theme
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="theme-card">
|
||||
<div class="bg-purple-600 h-2"></div>
|
||||
<div class="theme-preview bg-purple-50 flex items-center justify-center p-4">
|
||||
<div class="w-full bg-white rounded-lg shadow-md p-4 bg-opacity-80 backdrop-filter backdrop-blur-sm">
|
||||
<div class="flex">
|
||||
<div class="flex-shrink-0">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-purple-500" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path d="M2 10.5a1.5 1.5 0 113 0v6a1.5 1.5 0 01-3 0v-6zM6 10.333v5.43a2 2 0 001.106 1.79l.05.025A4 4 0 008.943 18h5.416a2 2 0 001.962-1.608l1.2-6A2 2 0 0015.56 8H12V4a2 2 0 00-2-2 1 1 0 00-1 1v.667a4 4 0 01-.8 2.4L6.8 7.933a4 4 0 00-.8 2.4z" />
|
||||
</svg>
|
||||
</div>
|
||||
<div class="ml-3">
|
||||
<p class="text-sm font-medium text-gray-900">Crystal Theme</p>
|
||||
<p class="text-xs text-gray-500">Transparent with blur effects</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-4">
|
||||
<h3 class="text-lg font-semibold mb-2">Crystal</h3>
|
||||
<p class="text-gray-600 text-sm mb-4">A modern glass-like theme with transparency and blur effects.</p>
|
||||
<button class="w-full btn btn-primary theme-demo" data-theme="crystal">
|
||||
Preview Theme
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="theme-card">
|
||||
<div class="bg-amber-500 h-2"></div>
|
||||
<div class="theme-preview bg-amber-50 flex items-center justify-center p-4">
|
||||
<div class="w-full bg-white rounded-lg shadow-md p-4">
|
||||
<div class="flex">
|
||||
<div class="flex-shrink-0 bg-amber-100 p-1 rounded">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-amber-500" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path fill-rule="evenodd" d="M18 3a1 1 0 00-1.447-.894L8.763 6H5a3 3 0 000 6h.28l1.771 5.316A1 1 0 008 18h1a1 1 0 001-1v-4.382l6.553 3.276A1 1 0 0018 15V3z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
</div>
|
||||
<div class="ml-3">
|
||||
<p class="text-sm font-medium text-gray-900">Amazon Theme</p>
|
||||
<p class="text-xs text-gray-500">Inspired by Amazon's notification style</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-4">
|
||||
<h3 class="text-lg font-semibold mb-2">Amazon</h3>
|
||||
<p class="text-gray-600 text-sm mb-4">Inspired by Amazon's notification style with distinctive icons.</p>
|
||||
<button class="w-full btn btn-primary theme-demo" data-theme="amazon">
|
||||
Preview Theme
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-white rounded-lg shadow-md overflow-hidden mb-8">
|
||||
<div class="p-6">
|
||||
<h2 class="text-xl font-bold mb-4">Using Themes in Your Code</h2>
|
||||
<p class="text-gray-600 mb-4">
|
||||
You can specify which theme to use for each notification using the <code>option()</code> method:
|
||||
</p>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>PHP</span>
|
||||
</div>
|
||||
<pre><code class="language-php">// Using the default theme
|
||||
flash()->success('Your profile has been updated successfully!');
|
||||
|
||||
// Using the Emerald theme
|
||||
flash()->option('theme', 'emerald')
|
||||
->success('Your profile has been updated successfully!');
|
||||
|
||||
// Using the Sapphire theme with additional options
|
||||
flash()->option('theme', 'sapphire')
|
||||
->option('position', 'bottom-right')
|
||||
->option('timeout', 5000)
|
||||
->info('You have 3 unread messages.');
|
||||
|
||||
// Using the Amazon theme
|
||||
flash()->option('theme', 'amazon')
|
||||
->warning('Your subscription will expire in 3 days.');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-white rounded-lg shadow-md overflow-hidden mb-8">
|
||||
<div class="p-6">
|
||||
<h2 class="text-xl font-bold mb-4">Theme Configuration</h2>
|
||||
<p class="text-gray-600 mb-4">
|
||||
You can configure themes globally in your configuration file:
|
||||
</p>
|
||||
|
||||
<div class="code-block mb-6">
|
||||
<div class="code-header">
|
||||
<span>YAML</span>
|
||||
</div>
|
||||
<pre><code class="language-yaml"># config/packages/flasher.yaml
|
||||
flasher:
|
||||
# Set the default theme for all notifications
|
||||
default: theme.amazon
|
||||
|
||||
themes:
|
||||
amazon:
|
||||
scripts:
|
||||
- '/vendor/flasher/themes/amazon/amazon.min.js'
|
||||
styles:
|
||||
- '/vendor/flasher/flasher.min.css'
|
||||
- '/vendor/flasher/themes/amazon/amazon.min.css'
|
||||
options:
|
||||
position: 'bottom-right'
|
||||
timeout: 6000
|
||||
|
||||
emerald:
|
||||
scripts:
|
||||
- '/vendor/flasher/themes/emerald/emerald.min.js'
|
||||
styles:
|
||||
- '/vendor/flasher/flasher.min.css'
|
||||
- '/vendor/flasher/themes/emerald/emerald.min.css'
|
||||
options:
|
||||
position: 'top-right'
|
||||
timeout: 5000</code></pre>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 mb-4">
|
||||
Each theme can have its own default options, scripts, and styles. This allows you to create a consistent notification experience throughout your application.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-white rounded-lg shadow-md overflow-hidden">
|
||||
<div class="p-6">
|
||||
<h2 class="text-xl font-bold mb-4">Custom Theme Templates</h2>
|
||||
<p class="text-gray-600 mb-4">
|
||||
Need something more customized? PHPFlasher allows you to create your own themes:
|
||||
</p>
|
||||
|
||||
<div class="code-block mb-6">
|
||||
<div class="code-header">
|
||||
<span>YAML</span>
|
||||
</div>
|
||||
<pre><code class="language-yaml"># config/packages/flasher.yaml
|
||||
flasher:
|
||||
themes:
|
||||
custom_theme:
|
||||
scripts:
|
||||
- '/assets/js/custom-theme.js'
|
||||
styles:
|
||||
- '/assets/css/custom-theme.css'
|
||||
options:
|
||||
position: 'top-center'
|
||||
timeout: 7000
|
||||
# Add any custom options your theme supports</code></pre>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 mb-4">
|
||||
Then you can use your custom theme in your code:
|
||||
</p>
|
||||
|
||||
<div class="code-block mb-6">
|
||||
<div class="code-header">
|
||||
<span>PHP</span>
|
||||
</div>
|
||||
<pre><code class="language-php">flash()->option('theme', 'custom_theme')
|
||||
->success('This uses your custom theme!');</code></pre>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-center">
|
||||
<a href="{{ path('app_theme_builder') }}" class="btn btn-primary">
|
||||
Try the Theme Builder
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block javascripts %}
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const themeButtons = document.querySelectorAll('.theme-demo');
|
||||
|
||||
themeButtons.forEach(button => {
|
||||
button.addEventListener('click', function() {
|
||||
const theme = this.getAttribute('data-theme');
|
||||
const messages = {
|
||||
'flasher': 'This notification uses the Flasher theme!',
|
||||
'emerald': 'This notification uses the Emerald theme!',
|
||||
'sapphire': 'This notification uses the Sapphire theme!',
|
||||
'crystal': 'This notification uses the Crystal theme!',
|
||||
'amazon': 'This notification uses the Amazon theme!'
|
||||
};
|
||||
|
||||
// Send AJAX request to show notification
|
||||
fetch('{{ path('app_show_notification') }}', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Requested-With': 'XMLHttpRequest'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
type: 'success',
|
||||
message: messages[theme] || 'Theme preview',
|
||||
options: {
|
||||
theme: theme
|
||||
}
|
||||
})
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,200 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block title %}Notification Types{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="mb-8">
|
||||
<h1 class="section-title">Notification Types</h1>
|
||||
<p class="section-subtitle">PHPFlasher supports four notification types for different scenarios.</p>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-8">
|
||||
{# Success #}
|
||||
<div class="card">
|
||||
<div class="h-2 bg-emerald-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<div class="flex items-center space-x-3">
|
||||
<div class="p-3 bg-emerald-100 rounded-xl">
|
||||
<svg class="w-8 h-8 text-emerald-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="text-2xl font-bold text-gray-800">Success</h2>
|
||||
<p class="text-gray-500">Positive feedback</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 mb-4">Use success notifications for completed actions, confirmations, and positive feedback.</p>
|
||||
|
||||
<div class="space-y-2 mb-6">
|
||||
<button onclick="showNotification({type: 'success', message: 'Your profile has been updated successfully!'})"
|
||||
class="btn btn-success w-full justify-start">
|
||||
Profile Updated
|
||||
</button>
|
||||
<button onclick="showNotification({type: 'success', message: 'Your account has been created. Welcome aboard!', title: 'Account Created'})"
|
||||
class="btn btn-success w-full justify-start">
|
||||
Account Created
|
||||
</button>
|
||||
<button onclick="showNotification({type: 'success', message: 'Payment of $99.00 confirmed. Receipt sent to your email.', title: 'Payment Successful'})"
|
||||
class="btn btn-success w-full justify-start">
|
||||
Payment Confirmed
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>PHP</span>
|
||||
</div>
|
||||
<pre class="!m-0"><code class="language-php">flash()->success('Profile updated successfully!');
|
||||
|
||||
// With title
|
||||
flash()->success('Welcome aboard!', 'Account Created');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# Error #}
|
||||
<div class="card">
|
||||
<div class="h-2 bg-rose-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<div class="flex items-center space-x-3">
|
||||
<div class="p-3 bg-rose-100 rounded-xl">
|
||||
<svg class="w-8 h-8 text-rose-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="text-2xl font-bold text-gray-800">Error</h2>
|
||||
<p class="text-gray-500">Failures and issues</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 mb-4">Use error notifications for validation failures, server errors, and problems.</p>
|
||||
|
||||
<div class="space-y-2 mb-6">
|
||||
<button onclick="showNotification({type: 'error', message: 'Invalid email or password. Please try again.'})"
|
||||
class="btn btn-danger w-full justify-start">
|
||||
Login Failed
|
||||
</button>
|
||||
<button onclick="showNotification({type: 'error', message: 'Your card was declined. Please try another payment method.', title: 'Payment Failed'})"
|
||||
class="btn btn-danger w-full justify-start">
|
||||
Payment Declined
|
||||
</button>
|
||||
<button onclick="showNotification({type: 'error', message: 'Unable to connect to server. Please check your connection.', title: 'Connection Error'})"
|
||||
class="btn btn-danger w-full justify-start">
|
||||
Server Error
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>PHP</span>
|
||||
</div>
|
||||
<pre class="!m-0"><code class="language-php">flash()->error('Invalid credentials.');
|
||||
|
||||
// With title
|
||||
flash()->error('Please try again.', 'Payment Failed');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# Warning #}
|
||||
<div class="card">
|
||||
<div class="h-2 bg-amber-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<div class="flex items-center space-x-3">
|
||||
<div class="p-3 bg-amber-100 rounded-xl">
|
||||
<svg class="w-8 h-8 text-amber-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="text-2xl font-bold text-gray-800">Warning</h2>
|
||||
<p class="text-gray-500">Caution alerts</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 mb-4">Use warning notifications to alert users about potential issues or important notices.</p>
|
||||
|
||||
<div class="space-y-2 mb-6">
|
||||
<button onclick="showNotification({type: 'warning', message: 'Your session will expire in 5 minutes.'})"
|
||||
class="btn btn-warning w-full justify-start">
|
||||
Session Expiring
|
||||
</button>
|
||||
<button onclick="showNotification({type: 'warning', message: 'You have unsaved changes that will be lost.', title: 'Unsaved Changes'})"
|
||||
class="btn btn-warning w-full justify-start">
|
||||
Unsaved Changes
|
||||
</button>
|
||||
<button onclick="showNotification({type: 'warning', message: 'Only 2 items left in stock!', title: 'Low Stock'})"
|
||||
class="btn btn-warning w-full justify-start">
|
||||
Low Stock Alert
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>PHP</span>
|
||||
</div>
|
||||
<pre class="!m-0"><code class="language-php">flash()->warning('Session expiring soon.');
|
||||
|
||||
// With title
|
||||
flash()->warning('Only 2 left!', 'Low Stock');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# Info #}
|
||||
<div class="card">
|
||||
<div class="h-2 bg-sky-500"></div>
|
||||
<div class="card-body">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<div class="flex items-center space-x-3">
|
||||
<div class="p-3 bg-sky-100 rounded-xl">
|
||||
<svg class="w-8 h-8 text-sky-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="text-2xl font-bold text-gray-800">Info</h2>
|
||||
<p class="text-gray-500">Neutral information</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-gray-600 mb-4">Use info notifications for tips, updates, and general information.</p>
|
||||
|
||||
<div class="space-y-2 mb-6">
|
||||
<button onclick="showNotification({type: 'info', message: 'A new version is available. Click here to update.'})"
|
||||
class="btn btn-info w-full justify-start">
|
||||
Update Available
|
||||
</button>
|
||||
<button onclick="showNotification({type: 'info', message: 'Tip: You can use keyboard shortcuts for faster navigation.', title: 'Pro Tip'})"
|
||||
class="btn btn-info w-full justify-start">
|
||||
Helpful Tip
|
||||
</button>
|
||||
<button onclick="showNotification({type: 'info', message: 'Your report is being generated and will be ready shortly.'})"
|
||||
class="btn btn-info w-full justify-start">
|
||||
Processing Status
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="code-block">
|
||||
<div class="code-header">
|
||||
<span>PHP</span>
|
||||
</div>
|
||||
<pre class="!m-0"><code class="language-php">flash()->info('New version available!');
|
||||
|
||||
// With title
|
||||
flash()->info('Use shortcuts!', 'Pro Tip');</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user