Skip to content

Instantly share code, notes, and snippets.

@burnz
Forked from binaryweavers/AnyLivewireComponent.php
Created April 22, 2021 06:54
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save burnz/70ab9ebd493b8cb4ce5163f276f5f0a6 to your computer and use it in GitHub Desktop.
Save burnz/70ab9ebd493b8cb4ce5163f276f5f0a6 to your computer and use it in GitHub Desktop.
Fluent toaster(alerts) for laravel/livewire using alpinejs and tailwindcss
public function showToasters(){
// default info toaster with timeout
$this->toaster('your message');
// makes it persistent
$this->toaster('your message')->persistent();
// warning toaster with timeout
$this->toaster('your message')->warning();
//And so on
//By using __destruct() we have made Toaster a Pending Object. So you can use methods in any order
$this->toaster('your message')->error()->persistent();
$this->toaster()->success('give message to type method if you want')->persistent();
$this->toaster()->timeout(15000)->info('give message to type method if you want');
}
//Don't forget to add toaster.blade.php to you layout file
@include('toasters.blade.php')
//Or if it is a blade component
<x-toasters></x-toasters>
public function boot(){
Livewire\Component::macro('toaster', function (?string $message = null, ?string $type = "info"): Toaster
{
return new Toaster($message, $type, $this);
});
}
//you can use toaster elsewhere in laravel as well add the helper for luxury (❁´◡`❁)
//helpers.php
function toaster(?string $message = null, ?string $type = 'info'){
return new App\Support\Toaster($message,$type);
}
<?php
namespace App\Support;
use Livewire\Component;
class Toaster
{
public ?Component $component = null;
public string $message;
public string $type;
public bool $persistent = false;
public int $timeout = 5000;
public function __construct(?string $message = null, ?string $type = "info", ?Component &$component = null)
{
$this->component = $component;
$this->message = $message;
$this->type = $type;
}
public function message(string $message = null, string $type = "info")
{
$this->type = $type;
if ($message) {
$this->message = $message;
}
return $this;
}
public function success(?string $message = null)
{
return $this->message($message, 'success');
}
public function info(?string $message = null)
{
return $this->message($message, 'info';
}
public function warning(?string $message = null)
{
return $this->message($message, 'warning');
}
public function error(?string $message = null)
{
return $this->message($message, 'error');
}
public function persistent()
{
$this->persistent = true;
return $this;
}
public function timeout(int $milliseconds){
$this->timeout = $milliseconds;
return $this;
}
public function generate()
{
if (!$this->message) {
return;
}
$payload = [
"type" => ($this->type ?: "info"),
"message" => $this->message,
"persistent" => $this->persistent,
"timeout" => $this->timeout
];
if ($this->component && empty($this->component->redirectTo)) {
$this->component->dispatchBrowserEvent('livewire-toaster', $payload);
} else {
session()->flash('livewire.toaster', $payload);
}
}
public function __destruct()
{
$this->generate();
}
}
<div x-cloak
x-data="toaster()"
x-init="init()"
x-on:livewire-toaster.window="trigger"
class="fixed bottom-0 right-0 flex flex-col max-w-sm p-4 space-y-3 w-80">
<template x-for="(toast,index) in toasters" :key="index">
<div x-show="toasters.indexOf(toast) >= 0"
x-transition:enter="transition ease-out duration-300"
x-transition:enter-start="opacity-0 transform scale-50"
x-transition:enter-end="opacity-100 transform scale-100"
x-transition:leave="transition ease-in duration-300"
x-transition:leave-start="opacity-100 transform scale-100"
x-transition:leave-end="opacity-0 transform scale-50">
<div class="flex items-center justify-between w-full px-2 py-3 space-x-6 shadow-lg toaster"
:class="toast.type">
<span x-html="toast.message" class="mr-2 capitalize"></span>
<button class="p-0.5 btn rounded-full error low focus:outline-none focusable"
x-on:click="close(toast)" x-show="toast.persistent">
<x-icon name="close" />
</button>
</div>
</div>
</template>
</div>
<script>
function toaster() {
return {
toasters: [],
flash: JSON.parse(JSON.stringify(@json(session('livewire.toaster')))),
trigger(event = null) {
if (event == null) return;
this.flash = event.detail ? event.detail : event;
let toast = {
type: this.flash.type,
message: this.flash.message,
persistent: this.flash.persistent,
timeout:this.flash.timeout
}
this.toasters.push(toast)
if (!toast.persistent) {
this.autoClose(toast)
}
},
autoClose(toast) {
setTimeout(() => {
this.close(toast)
}, toast.timeout);
},
close(toast) {
this.toasters.splice(this.toasters.indexOf(toast), 1)
},
init() {
if (this.flash) {
this.trigger(this.flash)
}
},
}
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment