From e997d0deeaf3d22af967324ed572726a8b57bba5 Mon Sep 17 00:00:00 2001 From: Saeed Vaziry <61919774+saeedvaziry@users.noreply.github.com> Date: Sun, 7 Jan 2024 09:54:08 +0100 Subject: [PATCH] WIP notifications and other refactors (#88) * WIP notifications and other refactors - refactor notification channels - send notifications on events related to the servers and sites - delete server log files on server deletion - add telegram notification channel - add new icons - cache configs and icons on installation and updates - new navbar for dark mode and settings * discord channel * build assets * pint --- .env.example | 4 +- .env.prod | 4 +- .env.sail | 4 +- .../NotificationChannels/AddChannel.php | 13 +- app/Contracts/Notification.php | 12 +- app/Contracts/NotificationChannel.php | 8 +- app/Enums/NotificationChannel.php | 2 + app/Facades/Notifier.php | 17 + app/Helpers/Notifier.php | 19 + app/Http/Controllers/GitHookController.php | 5 +- .../NotificationChannels/AddChannel.php | 4 + app/Jobs/Server/CheckConnection.php | 4 +- app/Mail/NotificationChannelMessage.php | 47 -- app/Mail/NotificationMail.php | 25 + app/Models/NotificationChannel.php | 29 +- app/Models/Server.php | 11 +- app/Models/ServerLog.php | 11 + app/Models/Site.php | 7 +- .../AbstractNotificationChannel.php | 13 + app/NotificationChannels/AbstractProvider.php | 16 - app/NotificationChannels/Discord.php | 49 +- app/NotificationChannels/Email.php | 38 +- app/NotificationChannels/Slack.php | 49 +- app/NotificationChannels/Telegram.php | 67 +++ app/Notifications/AbstractNotification.php | 36 ++ .../FailedToDeleteServerFromProvider.php | 17 +- app/Notifications/SSLExpirationAlert.php | 26 - app/Notifications/ServerDisconnected.php | 17 +- .../ServerInstallationFailed.php | 17 +- .../ServerInstallationStarted.php | 17 +- .../ServerInstallationSucceed.php | 12 +- app/Notifications/SiteInstallationFailed.php | 30 ++ app/Notifications/SiteInstallationSucceed.php | 29 ++ .../SourceControlDisconnected.php | 35 +- app/Providers/AppServiceProvider.php | 4 + app/ServerProviders/AWS.php | 11 +- app/ServerProviders/DigitalOcean.php | 9 +- app/ServerProviders/Hetzner.php | 9 +- app/ServerProviders/Linode.php | 9 +- app/ServerProviders/Vultr.php | 9 +- app/ServerTypes/Database.php | 7 +- app/ServerTypes/Regular.php | 7 +- app/SiteTypes/AbstractSiteType.php | 5 - app/Support/helpers.php | 8 + composer.json | 8 +- composer.lock | 475 +++++++++++++++++- config/core.php | 3 + install/install.sh | 5 + public/build/assets/app-8b808e33.css | 1 + public/build/assets/app-f482c864.css | 1 - public/build/manifest.json | 2 +- .../views/components/dropdown-link.blade.php | 2 +- resources/views/components/dropdown.blade.php | 2 +- resources/views/layouts/app.blade.php | 95 +--- resources/views/layouts/navigation.blade.php | 61 +-- .../layouts/partials/color-scheme.blade.php | 63 ++- .../add-channel.blade.php | 18 + .../channels-list.blade.php | 4 +- .../icons/discord.blade.php | 1 + .../icons/email.blade.php | 1 + .../icons/slack.blade.php | 1 + .../icons/telegram.blade.php | 1 + .../icons/bitbucket-icon.blade.php | 1 + .../icons/github-icon.blade.php | 1 + .../icons/gitlab-icon.blade.php | 1 + .../partials/bitbucket-icon.blade.php | 12 - .../partials/github-icon.blade.php | 3 - .../partials/gitlab-icon.blade.php | 10 - .../source-controls-list.blade.php | 4 +- .../views/livewire/user-dropdown.blade.php | 25 +- .../Feature/Http/NotificationChannelsTest.php | 55 +- update.sh | 1 + 72 files changed, 1151 insertions(+), 478 deletions(-) create mode 100644 app/Facades/Notifier.php create mode 100644 app/Helpers/Notifier.php delete mode 100644 app/Mail/NotificationChannelMessage.php create mode 100644 app/Mail/NotificationMail.php create mode 100644 app/NotificationChannels/AbstractNotificationChannel.php delete mode 100644 app/NotificationChannels/AbstractProvider.php create mode 100644 app/NotificationChannels/Telegram.php create mode 100644 app/Notifications/AbstractNotification.php delete mode 100644 app/Notifications/SSLExpirationAlert.php create mode 100644 app/Notifications/SiteInstallationFailed.php create mode 100644 app/Notifications/SiteInstallationSucceed.php create mode 100644 public/build/assets/app-8b808e33.css delete mode 100644 public/build/assets/app-f482c864.css create mode 100644 resources/views/livewire/notification-channels/icons/discord.blade.php create mode 100644 resources/views/livewire/notification-channels/icons/email.blade.php create mode 100644 resources/views/livewire/notification-channels/icons/slack.blade.php create mode 100644 resources/views/livewire/notification-channels/icons/telegram.blade.php create mode 100644 resources/views/livewire/source-controls/icons/bitbucket-icon.blade.php create mode 100644 resources/views/livewire/source-controls/icons/github-icon.blade.php create mode 100644 resources/views/livewire/source-controls/icons/gitlab-icon.blade.php delete mode 100644 resources/views/livewire/source-controls/partials/bitbucket-icon.blade.php delete mode 100644 resources/views/livewire/source-controls/partials/github-icon.blade.php delete mode 100644 resources/views/livewire/source-controls/partials/gitlab-icon.blade.php diff --git a/.env.example b/.env.example index ea5ea71c..bf21e047 100755 --- a/.env.example +++ b/.env.example @@ -26,8 +26,8 @@ REDIS_PASSWORD=null REDIS_PORT=6379 MAIL_MAILER=smtp -MAIL_HOST=mailhog -MAIL_PORT=1025 +MAIL_HOST= +MAIL_PORT= MAIL_USERNAME=null MAIL_PASSWORD=null MAIL_ENCRYPTION=null diff --git a/.env.prod b/.env.prod index fbb3b894..8b391567 100755 --- a/.env.prod +++ b/.env.prod @@ -26,8 +26,8 @@ REDIS_PASSWORD=null REDIS_PORT=6379 MAIL_MAILER=smtp -MAIL_HOST=mailhog -MAIL_PORT=1025 +MAIL_HOST= +MAIL_PORT= MAIL_USERNAME=null MAIL_PASSWORD=null MAIL_ENCRYPTION=null diff --git a/.env.sail b/.env.sail index 54c1437f..95118731 100644 --- a/.env.sail +++ b/.env.sail @@ -26,8 +26,8 @@ REDIS_PASSWORD=null REDIS_PORT=6379 MAIL_MAILER=smtp -MAIL_HOST=mailhog -MAIL_PORT=1025 +MAIL_HOST= +MAIL_PORT= MAIL_USERNAME=null MAIL_PASSWORD=null MAIL_ENCRYPTION=null diff --git a/app/Actions/NotificationChannels/AddChannel.php b/app/Actions/NotificationChannels/AddChannel.php index 091fd32d..2c3f7b8c 100644 --- a/app/Actions/NotificationChannels/AddChannel.php +++ b/app/Actions/NotificationChannels/AddChannel.php @@ -21,16 +21,25 @@ public function add(User $user, array $input): void 'label' => $input['label'], ]); $this->validateType($channel, $input); - $channel->data = $channel->provider()->data($input); + $channel->data = $channel->provider()->createData($input); $channel->save(); if (! $channel->provider()->connect()) { $channel->delete(); + if ($channel->provider === \App\Enums\NotificationChannel::EMAIL) { + throw ValidationException::withMessages([ + 'email' => __('Could not connect! Make sure you configured `.env` file correctly.'), + ]); + } + throw ValidationException::withMessages([ 'provider' => __('Could not connect'), ]); } + + $channel->connected = true; + $channel->save(); } /** @@ -49,7 +58,7 @@ protected function validate(array $input): void */ protected function validateType(NotificationChannel $channel, array $input): void { - Validator::make($input, $channel->provider()->validationRules()) + Validator::make($input, $channel->provider()->createRules($input)) ->validate(); } } diff --git a/app/Contracts/Notification.php b/app/Contracts/Notification.php index 4bcf3989..3e761fc8 100644 --- a/app/Contracts/Notification.php +++ b/app/Contracts/Notification.php @@ -2,9 +2,17 @@ namespace App\Contracts; +use Illuminate\Notifications\Messages\MailMessage; + interface Notification { - public function subject(): string; + public function rawText(): string; + + public function toMail(object $notifiable): MailMessage; + + public function toSlack(object $notifiable): string; + + public function toDiscord(object $notifiable): string; - public function message(bool $mail = false): mixed; + public function toTelegram(object $notifiable): string; } diff --git a/app/Contracts/NotificationChannel.php b/app/Contracts/NotificationChannel.php index 0297fa37..a4bf6997 100644 --- a/app/Contracts/NotificationChannel.php +++ b/app/Contracts/NotificationChannel.php @@ -4,11 +4,13 @@ interface NotificationChannel { - public function validationRules(): array; + public function createRules(array $input): array; - public function data(array $input): array; + public function createData(array $input): array; + + public function data(): array; public function connect(): bool; - public function sendMessage(string $subject, string $text): void; + public function send(object $notifiable, Notification $notification): void; } diff --git a/app/Enums/NotificationChannel.php b/app/Enums/NotificationChannel.php index 743a2264..6e088719 100644 --- a/app/Enums/NotificationChannel.php +++ b/app/Enums/NotificationChannel.php @@ -11,4 +11,6 @@ final class NotificationChannel extends Enum const SLACK = 'slack'; const DISCORD = 'discord'; + + const TELEGRAM = 'telegram'; } diff --git a/app/Facades/Notifier.php b/app/Facades/Notifier.php new file mode 100644 index 00000000..f56fae84 --- /dev/null +++ b/app/Facades/Notifier.php @@ -0,0 +1,17 @@ +site->deploy(); } catch (SourceControlIsNotConnected) { - // TODO: send notification + Notifier::send($gitHook->sourceControl, new SourceControlDisconnected($gitHook->sourceControl)); } catch (Throwable $e) { Log::error('git-hook-exception', (array) $e); } diff --git a/app/Http/Livewire/NotificationChannels/AddChannel.php b/app/Http/Livewire/NotificationChannels/AddChannel.php index 5b8d6a57..9acd6e55 100644 --- a/app/Http/Livewire/NotificationChannels/AddChannel.php +++ b/app/Http/Livewire/NotificationChannels/AddChannel.php @@ -15,6 +15,10 @@ class AddChannel extends Component public string $email; + public string $bot_token; + + public string $chat_id; + public function add(): void { app(\App\Actions\NotificationChannels\AddChannel::class)->add( diff --git a/app/Jobs/Server/CheckConnection.php b/app/Jobs/Server/CheckConnection.php index 08b3770c..4165a2d6 100644 --- a/app/Jobs/Server/CheckConnection.php +++ b/app/Jobs/Server/CheckConnection.php @@ -3,8 +3,10 @@ namespace App\Jobs\Server; use App\Events\Broadcast; +use App\Facades\Notifier; use App\Jobs\Job; use App\Models\Server; +use App\Notifications\ServerDisconnected; use Throwable; class CheckConnection extends Job @@ -39,7 +41,7 @@ public function failed(): void { $this->server->status = 'disconnected'; $this->server->save(); - /** @todo notify */ + Notifier::send($this->server, new ServerDisconnected($this->server)); event( new Broadcast('server-status-failed', [ 'server' => $this->server, diff --git a/app/Mail/NotificationChannelMessage.php b/app/Mail/NotificationChannelMessage.php deleted file mode 100644 index 24219d31..00000000 --- a/app/Mail/NotificationChannelMessage.php +++ /dev/null @@ -1,47 +0,0 @@ -subject = $subject; - $this->text = $text; - } - - /** - * Build the message. - * - * @return $this - */ - public function build() - { - if ($this->text instanceof MailMessage) { - return $this->markdown('vendor.notifications.email', $this->text->data()); - } - - return $this->markdown('emails.notification-channel-message', [ - 'subject' => $this->subject, - 'text' => $this->text, - ]); - } -} diff --git a/app/Mail/NotificationMail.php b/app/Mail/NotificationMail.php new file mode 100644 index 00000000..d0ecfe86 --- /dev/null +++ b/app/Mail/NotificationMail.php @@ -0,0 +1,25 @@ +subject = $subject; + $this->text = $text; + } + + public function build(): self + { + return $this->html($this->text); + } +} diff --git a/app/Models/NotificationChannel.php b/app/Models/NotificationChannel.php index b60b6822..cd8522c9 100644 --- a/app/Models/NotificationChannel.php +++ b/app/Models/NotificationChannel.php @@ -2,19 +2,21 @@ namespace App\Models; +use App\Contracts\Notification; use Illuminate\Database\Eloquent\Factories\HasFactory; +use Illuminate\Notifications\Notifiable; /** - * @property string $provider - * @property string $label - * @property array $data - * @property bool $connected - * @property bool $is_default - * @property User $user + * @property int $id + * @property string provider + * @property array data + * @property string label + * @property bool connected */ class NotificationChannel extends AbstractModel { use HasFactory; + use Notifiable; protected $fillable = [ 'provider', @@ -25,15 +27,24 @@ class NotificationChannel extends AbstractModel ]; protected $casts = [ - 'data' => 'json', + 'project_id' => 'integer', + 'data' => 'array', 'connected' => 'boolean', 'is_default' => 'boolean', ]; public function provider(): \App\Contracts\NotificationChannel { - $provider = config('core.notification_channels_providers_class')[$this->provider]; + $class = config('core.notification_channels_providers_class')[$this->provider]; - return new $provider($this); + return new $class($this); + } + + public static function notifyAll(Notification $notification): void + { + $channels = self::all(); + foreach ($channels as $channel) { + $channel->notify($notification); + } } } diff --git a/app/Models/Server.php b/app/Models/Server.php index 455e27ac..7f9860f7 100755 --- a/app/Models/Server.php +++ b/app/Models/Server.php @@ -4,15 +4,18 @@ use App\Contracts\ServerType; use App\Enums\ServerStatus; +use App\Facades\Notifier; use App\Facades\SSH; use App\Jobs\Installation\Upgrade; use App\Jobs\Server\CheckConnection; use App\Jobs\Server\RebootServer; +use App\Notifications\ServerInstallationStarted; use App\Support\Testing\SSHFake; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\Relations\HasMany; +use Illuminate\Filesystem\FilesystemAdapter; use Illuminate\Support\Facades\File; use Illuminate\Support\Facades\Storage; use Illuminate\Support\Str; @@ -110,7 +113,9 @@ public static function boot(): void $site->delete(); }); $server->provider()->delete(); - $server->logs()->delete(); + $server->logs()->each(function (ServerLog $log) { + $log->delete(); + }); $server->services()->delete(); $server->databases()->delete(); $server->databaseUsers()->delete(); @@ -239,7 +244,7 @@ public function getServiceByUnit($unit): ?Service public function install(): void { $this->type()->install(); - // $this->team->notify(new ServerInstallationStarted($this)); + Notifier::send($this, new ServerInstallationStarted($this)); } public function ssh(?string $user = null): \App\Helpers\SSH|SSHFake @@ -343,7 +348,7 @@ public function sshKey(): array ]; } - /** @var \Illuminate\Filesystem\FilesystemAdapter $storageDisk */ + /** @var FilesystemAdapter $storageDisk */ $storageDisk = Storage::disk(config('core.key_pairs_disk')); return [ diff --git a/app/Models/ServerLog.php b/app/Models/ServerLog.php index ab4a5ddf..d52c39a2 100755 --- a/app/Models/ServerLog.php +++ b/app/Models/ServerLog.php @@ -34,6 +34,17 @@ class ServerLog extends AbstractModel 'site_id' => 'integer', ]; + public static function boot(): void + { + parent::boot(); + + static::deleting(function (ServerLog $log) { + if (Storage::disk($log->disk)->exists($log->name)) { + Storage::disk($log->disk)->delete($log->name); + } + }); + } + public function getRouteKey(): string { return 'log'; diff --git a/app/Models/Site.php b/app/Models/Site.php index f8bbb475..14c94bea 100755 --- a/app/Models/Site.php +++ b/app/Models/Site.php @@ -8,10 +8,13 @@ use App\Enums\SslStatus; use App\Events\Broadcast; use App\Exceptions\SourceControlIsNotConnected; +use App\Facades\Notifier; use App\Jobs\Site\ChangePHPVersion; use App\Jobs\Site\Deploy; use App\Jobs\Site\DeployEnv; use App\Jobs\Site\UpdateBranch; +use App\Notifications\SiteInstallationFailed; +use App\Notifications\SiteInstallationSucceed; use Exception; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; @@ -406,7 +409,7 @@ public function installationFinished(): void 'site' => $this, ]) ); - /** @todo notify */ + Notifier::send($this, new SiteInstallationSucceed($this)); } /** @@ -422,7 +425,7 @@ public function installationFailed(Throwable $e): void 'site' => $this, ]) ); - /** @todo notify */ + Notifier::send($this, new SiteInstallationFailed($this)); Log::error('install-site-error', [ 'error' => (string) $e, ]); diff --git a/app/NotificationChannels/AbstractNotificationChannel.php b/app/NotificationChannels/AbstractNotificationChannel.php new file mode 100644 index 00000000..07d4468f --- /dev/null +++ b/app/NotificationChannels/AbstractNotificationChannel.php @@ -0,0 +1,13 @@ +notificationChannel = $notificationChannel; - } -} diff --git a/app/NotificationChannels/Discord.php b/app/NotificationChannels/Discord.php index bb0e6be2..14fcc491 100644 --- a/app/NotificationChannels/Discord.php +++ b/app/NotificationChannels/Discord.php @@ -2,21 +2,34 @@ namespace App\NotificationChannels; +use App\Contracts\Notification; use Illuminate\Support\Facades\Http; -class Discord extends AbstractProvider +class Discord extends AbstractNotificationChannel { - public function validationRules(): array + public function channel(): string + { + return 'discord'; + } + + public function createRules(array $input): array { return [ 'webhook_url' => 'required|url', ]; } - public function data(array $input): array + public function createData(array $input): array + { + return [ + 'webhook_url' => $input['webhook_url'] ?? '', + ]; + } + + public function data(): array { return [ - 'webhook_url' => $input['webhook_url'], + 'webhook_url' => $this->notificationChannel->data['webhook_url'] ?? '', ]; } @@ -24,35 +37,37 @@ public function connect(): bool { $connect = $this->checkConnection( __('Congratulations! 🎉'), - __("You've connected your Discord to Vito")."\n". + __("You've connected your Discord to :app", ['app' => config('app.name')])."\n". __('Manage your notification channels')."\n". route('notification-channels') ); if (! $connect) { + $this->notificationChannel->delete(); + return false; } - return true; - } + $this->notificationChannel->connected = true; + $this->notificationChannel->save(); - public function sendMessage(string $subject, string $text): void - { - dispatch(function () use ($subject, $text) { - $data = $this->notificationChannel->data; - Http::post($data['webhook_url'], [ - 'content' => '*'.$subject.'*'."\n".$text, - ]); - }); + return true; } private function checkConnection(string $subject, string $text): bool { - $data = $this->notificationChannel->data; - $connect = Http::post($data['webhook_url'], [ + $connect = Http::post($this->data()['webhook_url'], [ 'content' => '*'.$subject.'*'."\n".$text, ]); return $connect->ok(); } + + public function send(object $notifiable, Notification $notification): void + { + $data = $this->notificationChannel->data; + Http::post($data['webhook_url'], [ + 'content' => $notification->toSlack($notifiable), + ]); + } } diff --git a/app/NotificationChannels/Email.php b/app/NotificationChannels/Email.php index 8f5b86f8..f429764f 100644 --- a/app/NotificationChannels/Email.php +++ b/app/NotificationChannels/Email.php @@ -2,36 +2,56 @@ namespace App\NotificationChannels; -use App\Mail\NotificationChannelMessage; +use App\Contracts\Notification; +use App\Mail\NotificationMail; +use App\Models\NotificationChannel; use Illuminate\Support\Facades\Mail; +use Throwable; -class Email extends AbstractProvider +class Email extends AbstractNotificationChannel { - public function validationRules(): array + public function createRules(array $input): array { return [ 'email' => 'required|email', ]; } - public function data(array $input): array + public function createData(array $input): array { return [ 'email' => $input['email'], ]; } + public function data(): array + { + return [ + 'email' => $this->notificationChannel->data['email'] ?? '', + ]; + } + public function connect(): bool { - $this->notificationChannel->connected = true; - $this->notificationChannel->save(); + try { + Mail::to($this->data()['email'])->send( + new NotificationMail('Test VitoDeploy', 'This is a test email!') + ); + } catch (Throwable) { + return false; + } return true; } - public function sendMessage(string $subject, mixed $text): void + public function send(object $notifiable, Notification $notification): void { - $data = $this->notificationChannel->data; - Mail::to($data['email'])->send(new NotificationChannelMessage($subject, $text)); + /** @var NotificationChannel $notifiable */ + $this->notificationChannel = $notifiable; + $message = $notification->toMail($notifiable); + + Mail::to($this->data()['email'])->send( + new NotificationMail($message->subject, $message->render()) + ); } } diff --git a/app/NotificationChannels/Slack.php b/app/NotificationChannels/Slack.php index b6c31934..f5c368ba 100644 --- a/app/NotificationChannels/Slack.php +++ b/app/NotificationChannels/Slack.php @@ -2,21 +2,34 @@ namespace App\NotificationChannels; +use App\Contracts\Notification; use Illuminate\Support\Facades\Http; -class Slack extends AbstractProvider +class Slack extends AbstractNotificationChannel { - public function validationRules(): array + public function channel(): string + { + return 'slack'; + } + + public function createRules(array $input): array { return [ 'webhook_url' => 'required|url', ]; } - public function data(array $input): array + public function createData(array $input): array + { + return [ + 'webhook_url' => $input['webhook_url'] ?? '', + ]; + } + + public function data(): array { return [ - 'webhook_url' => $input['webhook_url'], + 'webhook_url' => $this->notificationChannel->data['webhook_url'] ?? '', ]; } @@ -24,35 +37,37 @@ public function connect(): bool { $connect = $this->checkConnection( __('Congratulations! 🎉'), - __("You've connected your Slack to Vito")."\n". + __("You've connected your Slack to :app", ['app' => config('app.name')])."\n". __('Manage your notification channels')."\n". route('notification-channels') ); if (! $connect) { + $this->notificationChannel->delete(); + return false; } - return true; - } + $this->notificationChannel->connected = true; + $this->notificationChannel->save(); - public function sendMessage(string $subject, string $text): void - { - dispatch(function () use ($subject, $text) { - $data = $this->notificationChannel->data; - Http::post($data['webhook_url'], [ - 'text' => '*'.$subject.'*'."\n".$text, - ]); - }); + return true; } private function checkConnection(string $subject, string $text): bool { - $data = $this->notificationChannel->data; - $connect = Http::post($data['webhook_url'], [ + $connect = Http::post($this->data()['webhook_url'], [ 'text' => '*'.$subject.'*'."\n".$text, ]); return $connect->ok(); } + + public function send(object $notifiable, Notification $notification): void + { + $data = $this->notificationChannel->data; + Http::post($data['webhook_url'], [ + 'text' => $notification->toSlack($notifiable), + ]); + } } diff --git a/app/NotificationChannels/Telegram.php b/app/NotificationChannels/Telegram.php new file mode 100644 index 00000000..dc9ee1c9 --- /dev/null +++ b/app/NotificationChannels/Telegram.php @@ -0,0 +1,67 @@ + 'required|string', + 'chat_id' => 'required', + ]; + } + + public function createData(array $input): array + { + return [ + 'bot_token' => $input['bot_token'], + 'chat_id' => $input['chat_id'], + ]; + } + + public function data(): array + { + return [ + 'bot_token' => $this->notificationChannel->data['bot_token'] ?? '', + 'chat_id' => $this->notificationChannel->data['chat_id'] ?? '', + ]; + } + + public function connect(): bool + { + try { + $this->sendToTelegram(__('Connected!')); + } catch (Throwable) { + return false; + } + + return true; + } + + public function send(object $notifiable, Notification $notification): void + { + $this->sendToTelegram($notification->toTelegram($notifiable)); + } + + private function sendToTelegram(string $text): void + { + Http::post($this->apiUrl.$this->data()['bot_token'].'/sendMessage', [ + 'chat_id' => $this->data()['chat_id'], + 'text' => $text, + 'parse_mode' => 'markdown', + 'disable_web_page_preview' => true, + ]); + } +} diff --git a/app/Notifications/AbstractNotification.php b/app/Notifications/AbstractNotification.php new file mode 100644 index 00000000..34a225ff --- /dev/null +++ b/app/Notifications/AbstractNotification.php @@ -0,0 +1,36 @@ +line($this->rawText()); + } + + public function toSlack(object $notifiable): string + { + return $this->rawText(); + } + + public function toDiscord(object $notifiable): string + { + return $this->rawText(); + } + + public function toTelegram(object $notifiable): string + { + return $this->rawText(); + } +} diff --git a/app/Notifications/FailedToDeleteServerFromProvider.php b/app/Notifications/FailedToDeleteServerFromProvider.php index f45b5985..08d8a56b 100644 --- a/app/Notifications/FailedToDeleteServerFromProvider.php +++ b/app/Notifications/FailedToDeleteServerFromProvider.php @@ -2,12 +2,11 @@ namespace App\Notifications; -use App\Contracts\Notification; use App\Models\Server; use Illuminate\Bus\Queueable; use Illuminate\Notifications\Messages\MailMessage; -class FailedToDeleteServerFromProvider implements Notification +class FailedToDeleteServerFromProvider extends AbstractNotification { use Queueable; @@ -18,26 +17,18 @@ public function __construct(Server $server) $this->server = $server; } - public function subject(): string + public function rawText(): string { - return __('Failed to delete the server from the provider!'); - } - - public function message(bool $mail = false): mixed - { - if ($mail) { - return $this->mail(); - } - return __("We couldn't delete [:server] \nfrom :provider \nPlease check your provider and delete it manually", [ 'server' => $this->server->name, 'provider' => $this->server->provider, ]); } - public function mail(): MailMessage + public function toMail(object $notifiable): MailMessage { return (new MailMessage) + ->subject(__('Failed to delete the server from the provider!')) ->line("We couldn't delete [".$this->server->name.'] from '.$this->server->provider) ->line('Please check your provider and delete it manually'); } diff --git a/app/Notifications/SSLExpirationAlert.php b/app/Notifications/SSLExpirationAlert.php deleted file mode 100644 index 0fb7b0ce..00000000 --- a/app/Notifications/SSLExpirationAlert.php +++ /dev/null @@ -1,26 +0,0 @@ -ssl = $ssl; - } - - public function subject(): string - { - return __('SSL expiring soon!'); - } - - public function message(bool $mail = false): string - { - return $this->ssl->site->domain."'s ".__('SSL is expiring on').' '.$this->ssl->expires_at->format('Y-m-d'); - } -} diff --git a/app/Notifications/ServerDisconnected.php b/app/Notifications/ServerDisconnected.php index 80cadb58..813f8d7d 100644 --- a/app/Notifications/ServerDisconnected.php +++ b/app/Notifications/ServerDisconnected.php @@ -2,11 +2,10 @@ namespace App\Notifications; -use App\Contracts\Notification; use App\Models\Server; use Illuminate\Notifications\Messages\MailMessage; -class ServerDisconnected implements Notification +class ServerDisconnected extends AbstractNotification { protected Server $server; @@ -15,25 +14,17 @@ public function __construct(Server $server) $this->server = $server; } - public function subject(): string + public function rawText(): string { - return __('Server disconnected!'); - } - - public function message(bool $mail = false): mixed - { - if ($mail) { - return $this->mail(); - } - return __("We've disconnected from your server [:server]", [ 'server' => $this->server->name, ]); } - public function mail(): MailMessage + public function toMail(object $notifiable): MailMessage { return (new MailMessage) + ->subject(__('Server disconnected!')) ->line("We've disconnected from your server [".$this->server->name.'].') ->line('Please check your sever is online and make sure that has our public keys in it'); } diff --git a/app/Notifications/ServerInstallationFailed.php b/app/Notifications/ServerInstallationFailed.php index f20dc4e8..e98731f3 100644 --- a/app/Notifications/ServerInstallationFailed.php +++ b/app/Notifications/ServerInstallationFailed.php @@ -2,11 +2,10 @@ namespace App\Notifications; -use App\Contracts\Notification; use App\Models\Server; use Illuminate\Notifications\Messages\MailMessage; -class ServerInstallationFailed implements Notification +class ServerInstallationFailed extends AbstractNotification { protected Server $server; @@ -15,26 +14,18 @@ public function __construct(Server $server) $this->server = $server; } - public function subject(): string + public function rawText(): string { - return __('Server installation failed!'); - } - - public function message(bool $mail = false): mixed - { - if ($mail) { - return $this->mail(); - } - return __("Installation failed for server [:server] \nCheck your server's logs \n:logs", [ 'server' => $this->server->name, 'logs' => url('/servers/'.$this->server->id.'/logs'), ]); } - private function mail(): MailMessage + public function toMail(object $notifiable): MailMessage { return (new MailMessage) + ->subject(__('Server installation failed!')) ->line('Your server ['.$this->server->name.'] installation has been failed.') ->line('Check your server logs') ->action('View Logs', url('/servers/'.$this->server->id.'/logs')); diff --git a/app/Notifications/ServerInstallationStarted.php b/app/Notifications/ServerInstallationStarted.php index ac9f00dc..a33511d6 100644 --- a/app/Notifications/ServerInstallationStarted.php +++ b/app/Notifications/ServerInstallationStarted.php @@ -2,11 +2,10 @@ namespace App\Notifications; -use App\Contracts\Notification; use App\Models\Server; use Illuminate\Notifications\Messages\MailMessage; -class ServerInstallationStarted implements Notification +class ServerInstallationStarted extends AbstractNotification { protected Server $server; @@ -15,26 +14,18 @@ public function __construct(Server $server) $this->server = $server; } - public function subject(): string + public function rawText(): string { - return __('Server installation started!'); - } - - public function message(bool $mail = false): mixed - { - if ($mail) { - return $this->mail(); - } - return __("Installation started for server [:server]\nThis may take several minutes depending on many things like your server's internet speed.\nAs soon as it finishes, We will notify you through this channel.\nYou can check the progress live on your dashboard.\n:progress", [ 'server' => $this->server->name, 'progress' => url('/servers/'.$this->server->id), ]); } - public function mail(): MailMessage + public function toMail(object $notifiable): MailMessage { return (new MailMessage) + ->subject(__('Server installation started!')) ->line('Your server\'s ['.$this->server->name.'] installation has been started.') ->line("This may take several minutes depending on many things like your server's internet speed.") ->line('As soon as it finishes, We will notify you through this channel.') diff --git a/app/Notifications/ServerInstallationSucceed.php b/app/Notifications/ServerInstallationSucceed.php index 0e3a5894..7b215572 100644 --- a/app/Notifications/ServerInstallationSucceed.php +++ b/app/Notifications/ServerInstallationSucceed.php @@ -2,11 +2,10 @@ namespace App\Notifications; -use App\Contracts\Notification; use App\Models\Server; use Illuminate\Notifications\Messages\MailMessage; -class ServerInstallationSucceed implements Notification +class ServerInstallationSucceed extends AbstractNotification { protected Server $server; @@ -20,14 +19,10 @@ public function subject(): string return __('Server installation succeed!'); } - public function message(bool $mail = false): mixed + public function rawText(): string { $this->server->refresh(); - if ($mail) { - return $this->mail(); - } - return __("Installation succeed for server [:server] \nServer IP: :ip \nUser: :user\nPassword: :password\n:link", [ 'server' => $this->server->name, 'ip' => $this->server->ip, @@ -37,11 +32,12 @@ public function message(bool $mail = false): mixed ]); } - public function mail(): MailMessage + public function toMail(object $notifiable): MailMessage { $this->server->refresh(); return (new MailMessage) + ->subject(__('Server installation succeed!')) ->line('Your server ['.$this->server->name.'] has been installed successfully.') ->line('Server IP: '.$this->server->ip) ->line('User: '.$this->server->authentication['user']) diff --git a/app/Notifications/SiteInstallationFailed.php b/app/Notifications/SiteInstallationFailed.php new file mode 100644 index 00000000..0c755186 --- /dev/null +++ b/app/Notifications/SiteInstallationFailed.php @@ -0,0 +1,30 @@ + $this->site->domain, + 'logs' => url('/servers/'.$this->site->server_id.'/logs'), + ]); + } + + public function toMail(object $notifiable): MailMessage + { + return (new MailMessage) + ->subject(__('Site installation failed!')) + ->line('Your site\'s ['.$this->site->domain.'] installation has been failed.') + ->line('Check your server logs') + ->action('View Logs', url('/servers/'.$this->site->server_id.'/logs')); + } +} diff --git a/app/Notifications/SiteInstallationSucceed.php b/app/Notifications/SiteInstallationSucceed.php new file mode 100644 index 00000000..e4c353e3 --- /dev/null +++ b/app/Notifications/SiteInstallationSucceed.php @@ -0,0 +1,29 @@ + $this->site->domain, + ]); + } + + public function toMail(object $notifiable): MailMessage + { + return (new MailMessage) + ->subject(__('Site installation succeed!')) + ->line('Your site\'s ['.$this->site->domain.'] installation has been installed.') + ->line('Check your site') + ->action('View Site', url('/servers/'.$this->site->server_id.'/sites/'.$this->site->id)); + } +} diff --git a/app/Notifications/SourceControlDisconnected.php b/app/Notifications/SourceControlDisconnected.php index 73e48c1e..ab732d55 100644 --- a/app/Notifications/SourceControlDisconnected.php +++ b/app/Notifications/SourceControlDisconnected.php @@ -2,41 +2,26 @@ namespace App\Notifications; -use Illuminate\Bus\Queueable; -use Illuminate\Contracts\Queue\ShouldQueue; +use App\Models\SourceControl; use Illuminate\Notifications\Messages\MailMessage; -use Illuminate\Notifications\Notification; -class SourceControlDisconnected extends Notification implements ShouldQueue +class SourceControlDisconnected extends AbstractNotification { - use Queueable; - - protected string $sourceControl; - - public function __construct(string $sourceControl) + public function __construct(protected SourceControl $sourceControl) { - $this->sourceControl = $sourceControl; } - public function via(): array + public function rawText(): string { - return ['mail']; + return __('Source control [:sourceControl] has been disconnected from Vito', [ + 'sourceControl' => $this->sourceControl->profile, + ]); } - public function toMail(): MailMessage + public function toMail(object $notifiable): MailMessage { return (new MailMessage) - ->subject('Lost connection to your '.$this->sourceControl) - ->line("We've lost connection to your $this->sourceControl account.") - ->line("We'll not able to do any deployments until you reconnect.") - ->line("To reconnect your $this->sourceControl account please click on the bellow button.") - ->action('Reconnect', url('/source-controls')); - } - - public function toArray(): array - { - return [ - // - ]; + ->subject(__('Source control disconnected!')) + ->line($this->rawText()); } } diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index 98a8c837..41c7bb14 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -2,6 +2,7 @@ namespace App\Providers; +use App\Helpers\Notifier; use App\Helpers\SSH; use App\Support\SocialiteProviders\DropboxProvider; use Illuminate\Contracts\Container\BindingResolutionException; @@ -29,6 +30,9 @@ public function boot(): void $this->app->bind('ssh', function () { return new SSH; }); + $this->app->bind('notifier', function () { + return new Notifier; + }); $this->extendSocialite(); } diff --git a/app/ServerProviders/AWS.php b/app/ServerProviders/AWS.php index 27a0eda4..ea8cebf2 100755 --- a/app/ServerProviders/AWS.php +++ b/app/ServerProviders/AWS.php @@ -4,10 +4,14 @@ use App\Enums\OperatingSystem; use App\Exceptions\CouldNotConnectToProvider; +use App\Facades\Notifier; +use App\Notifications\FailedToDeleteServerFromProvider; use Aws\Ec2\Ec2Client; use Aws\EC2InstanceConnect\EC2InstanceConnectClient; use Exception; +use Illuminate\Filesystem\FilesystemAdapter; use Illuminate\Support\Facades\Storage; +use Throwable; class AWS extends AbstractProvider { @@ -125,9 +129,8 @@ public function delete(): void $this->ec2Client->terminateInstances([ 'InstanceIds' => [$this->server->provider_data['instance_id']], ]); - } catch (Exception) { - /** @todo notify */ - // $this->server->team->notify(new FailedToDeleteServerFromProvider($this->server)); + } catch (Throwable) { + Notifier::send($this->server, new FailedToDeleteServerFromProvider($this->server)); } } } @@ -164,7 +167,7 @@ private function createKeyPair(): void $result = $this->ec2Client->createKeyPair([ 'KeyName' => $keyName, ]); - /** @var \Illuminate\Filesystem\FilesystemAdapter $storageDisk */ + /** @var FilesystemAdapter $storageDisk */ $storageDisk = Storage::disk(config('core.key_pairs_disk')); $storageDisk->put((string) $this->server->id, $result['KeyMaterial']); generate_public_key( diff --git a/app/ServerProviders/DigitalOcean.php b/app/ServerProviders/DigitalOcean.php index d677d041..8e60035b 100644 --- a/app/ServerProviders/DigitalOcean.php +++ b/app/ServerProviders/DigitalOcean.php @@ -4,6 +4,8 @@ use App\Exceptions\CouldNotConnectToProvider; use App\Exceptions\ServerProviderError; +use App\Facades\Notifier; +use App\Notifications\FailedToDeleteServerFromProvider; use Exception; use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Log; @@ -148,10 +150,9 @@ public function delete(): void $delete = Http::withToken($this->server->serverProvider->credentials['token']) ->delete($this->apiUrl.'/droplets/'.$this->server->provider_data['droplet_id']); - /** @todo notify */ - // if (! $delete->ok()) { - // $this->server->team->notify(new FailedToDeleteServerFromProvider($this->server)); - // } + if (! $delete->ok()) { + Notifier::send($this->server, new FailedToDeleteServerFromProvider($this->server)); + } } } } diff --git a/app/ServerProviders/Hetzner.php b/app/ServerProviders/Hetzner.php index b3f429f5..6cc42eee 100644 --- a/app/ServerProviders/Hetzner.php +++ b/app/ServerProviders/Hetzner.php @@ -4,6 +4,8 @@ use App\Exceptions\CouldNotConnectToProvider; use App\Exceptions\ServerProviderError; +use App\Facades\Notifier; +use App\Notifications\FailedToDeleteServerFromProvider; use Illuminate\Http\Client\Response; use Illuminate\Support\Facades\Http; @@ -122,10 +124,9 @@ public function delete(): void $delete = Http::withToken($this->server->serverProvider->credentials['token']) ->delete($this->apiUrl.'/servers/'.$this->server->provider_data['hetzner_id']); - /** @todo notify */ - // if (! $delete->ok()) { - // $this->server->team->notify(new FailedToDeleteServerFromProvider($this->server)); - // } + if (! $delete->ok()) { + Notifier::send($this->server, new FailedToDeleteServerFromProvider($this->server)); + } } // delete key diff --git a/app/ServerProviders/Linode.php b/app/ServerProviders/Linode.php index 02b17c63..b696c1ac 100644 --- a/app/ServerProviders/Linode.php +++ b/app/ServerProviders/Linode.php @@ -4,6 +4,8 @@ use App\Exceptions\CouldNotConnectToProvider; use App\Exceptions\ServerProviderError; +use App\Facades\Notifier; +use App\Notifications\FailedToDeleteServerFromProvider; use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Log; @@ -131,10 +133,9 @@ public function delete(): void $delete = Http::withToken($this->server->serverProvider->credentials['token']) ->delete($this->apiUrl.'/linode/instances/'.$this->server->provider_data['linode_id']); - /** @todo notify */ - // if (! $delete->ok()) { - // $this->server->team->notify(new FailedToDeleteServerFromProvider($this->server)); - // } + if (! $delete->ok()) { + Notifier::send($this->server, new FailedToDeleteServerFromProvider($this->server)); + } } } } diff --git a/app/ServerProviders/Vultr.php b/app/ServerProviders/Vultr.php index 2e64ca45..b8c2f05e 100644 --- a/app/ServerProviders/Vultr.php +++ b/app/ServerProviders/Vultr.php @@ -4,6 +4,8 @@ use App\Exceptions\CouldNotConnectToProvider; use App\Exceptions\ServerProviderError; +use App\Facades\Notifier; +use App\Notifications\FailedToDeleteServerFromProvider; use Exception; use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Log; @@ -144,10 +146,9 @@ public function delete(): void $delete = Http::withToken($this->server->serverProvider->credentials['token']) ->delete($this->apiUrl.'/instances/'.$this->server->provider_data['instance_id']); - /** @todo notify */ - // if (! $delete->ok()) { - // $this->server->team->notify(new FailedToDeleteServerFromProvider($this->server)); - // } + if (! $delete->ok()) { + Notifier::send($this->server, new FailedToDeleteServerFromProvider($this->server)); + } } } } diff --git a/app/ServerTypes/Database.php b/app/ServerTypes/Database.php index 86624f8a..984fe859 100755 --- a/app/ServerTypes/Database.php +++ b/app/ServerTypes/Database.php @@ -3,9 +3,12 @@ namespace App\ServerTypes; use App\Events\Broadcast; +use App\Facades\Notifier; use App\Jobs\Installation\Initialize; use App\Jobs\Installation\InstallRequirements; use App\Jobs\Installation\Upgrade; +use App\Notifications\ServerInstallationFailed; +use App\Notifications\ServerInstallationSucceed; use Illuminate\Support\Facades\Bus; use Illuminate\Support\Facades\Log; use Throwable; @@ -66,7 +69,7 @@ public function install(): void 'server' => $this->server, ]) ); - /** @todo notify */ + Notifier::send($this->server, new ServerInstallationSucceed($this->server)); }; Bus::chain($jobs) @@ -79,7 +82,7 @@ public function install(): void 'server' => $this->server, ]) ); - /** @todo notify */ + Notifier::send($this->server, new ServerInstallationFailed($this->server)); Log::error('server-installation-error', [ 'error' => (string) $e, ]); diff --git a/app/ServerTypes/Regular.php b/app/ServerTypes/Regular.php index a888958a..fe3c9969 100755 --- a/app/ServerTypes/Regular.php +++ b/app/ServerTypes/Regular.php @@ -4,12 +4,15 @@ use App\Enums\ServerStatus; use App\Events\Broadcast; +use App\Facades\Notifier; use App\Jobs\Installation\Initialize; use App\Jobs\Installation\InstallCertbot; use App\Jobs\Installation\InstallComposer; use App\Jobs\Installation\InstallNodejs; use App\Jobs\Installation\InstallRequirements; use App\Jobs\Installation\Upgrade; +use App\Notifications\ServerInstallationFailed; +use App\Notifications\ServerInstallationSucceed; use Illuminate\Support\Facades\Bus; use Illuminate\Support\Facades\Log; use Throwable; @@ -88,7 +91,7 @@ public function install(): void 'server' => $this->server, ]) ); - /** @todo notify */ + Notifier::send($this->server, new ServerInstallationSucceed($this->server)); }; Bus::chain($jobs) @@ -101,7 +104,7 @@ public function install(): void 'server' => $this->server, ]) ); - /** @todo notify */ + Notifier::send($this->server, new ServerInstallationFailed($this->server)); Log::error('server-installation-error', [ 'error' => (string) $e, ]); diff --git a/app/SiteTypes/AbstractSiteType.php b/app/SiteTypes/AbstractSiteType.php index 055e3653..22a29a8d 100755 --- a/app/SiteTypes/AbstractSiteType.php +++ b/app/SiteTypes/AbstractSiteType.php @@ -22,11 +22,6 @@ public function delete(): void dispatch(new DeleteSite($this->site))->onConnection('ssh'); } - public function install(): void - { - // TODO: Implement install() method. - } - protected function progress(int $percentage): Closure { return function () use ($percentage) { diff --git a/app/Support/helpers.php b/app/Support/helpers.php index a586b4c0..dc45fbac 100755 --- a/app/Support/helpers.php +++ b/app/Support/helpers.php @@ -1,5 +1,6 @@ format('Y-m-d H:i:s'); } + +function cast_to_json(array $json): Illuminate\Database\Query\Expression|Expression +{ + $json = addslashes(json_encode($json)); + + return DB::raw("CAST('{$json}' AS JSON)"); +} diff --git a/composer.json b/composer.json index 3331de92..e60d0562 100644 --- a/composer.json +++ b/composer.json @@ -6,18 +6,22 @@ "license": "MIT", "require": { "php": "^8.1", + "ext-ftp": "*", "aws/aws-sdk-php": "^3.158", "bensampo/laravel-enum": "^6.3", + "blade-ui-kit/blade-heroicons": "^2.2", + "davidhsianturi/blade-bootstrap-icons": "^1.4", "guzzlehttp/guzzle": "^7.2", + "khatabwedaa/blade-css-icons": "^1.3", "laravel/fortify": "^1.17", "laravel/framework": "^10.0", "laravel/sanctum": "^3.2", "laravel/socialite": "^5.2", "laravel/tinker": "^2.8", "livewire/livewire": "^2.12", - "phpseclib/phpseclib": "~3.0", "opcodesio/log-viewer": "^2.5", - "ext-ftp": "*" + "owenvoke/blade-fontawesome": "^2.5", + "phpseclib/phpseclib": "~3.0" }, "require-dev": { "fakerphp/faker": "^1.9.1", diff --git a/composer.lock b/composer.lock index d9fecb98..f80056af 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "bffd27708153bfce7c9dc34b975700de", + "content-hash": "b3f98cafe7fcc5d3ce67ad09a8f66661", "packages": [ { "name": "aws/aws-crt-php", @@ -300,6 +300,156 @@ ], "time": "2023-11-15T15:39:24+00:00" }, + { + "name": "blade-ui-kit/blade-heroicons", + "version": "2.2.1", + "source": { + "type": "git", + "url": "https://github.com/blade-ui-kit/blade-heroicons.git", + "reference": "bcf4be8f6bbde0bb4c23f2e3fb189b88dec1580a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/blade-ui-kit/blade-heroicons/zipball/bcf4be8f6bbde0bb4c23f2e3fb189b88dec1580a", + "reference": "bcf4be8f6bbde0bb4c23f2e3fb189b88dec1580a", + "shasum": "" + }, + "require": { + "blade-ui-kit/blade-icons": "^1.1", + "illuminate/support": "^9.0|^10.0", + "php": "^8.0" + }, + "require-dev": { + "orchestra/testbench": "^7.0|^8.0", + "phpunit/phpunit": "^9.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "BladeUI\\Heroicons\\BladeHeroiconsServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "BladeUI\\Heroicons\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Dries Vints", + "homepage": "https://driesvints.com" + } + ], + "description": "A package to easily make use of Heroicons in your Laravel Blade views.", + "homepage": "https://github.com/blade-ui-kit/blade-heroicons", + "keywords": [ + "Heroicons", + "blade", + "laravel" + ], + "support": { + "issues": "https://github.com/blade-ui-kit/blade-heroicons/issues", + "source": "https://github.com/blade-ui-kit/blade-heroicons/tree/2.2.1" + }, + "funding": [ + { + "url": "https://github.com/sponsors/driesvints", + "type": "github" + }, + { + "url": "https://www.paypal.com/paypalme/driesvints", + "type": "paypal" + } + ], + "time": "2023-12-18T20:44:03+00:00" + }, + { + "name": "blade-ui-kit/blade-icons", + "version": "1.5.3", + "source": { + "type": "git", + "url": "https://github.com/blade-ui-kit/blade-icons.git", + "reference": "b5e6603218e2347ac81cb780bc6f71c8c3b31f5b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/blade-ui-kit/blade-icons/zipball/b5e6603218e2347ac81cb780bc6f71c8c3b31f5b", + "reference": "b5e6603218e2347ac81cb780bc6f71c8c3b31f5b", + "shasum": "" + }, + "require": { + "illuminate/contracts": "^8.0|^9.0|^10.0", + "illuminate/filesystem": "^8.0|^9.0|^10.0", + "illuminate/support": "^8.0|^9.0|^10.0", + "illuminate/view": "^8.0|^9.0|^10.0", + "php": "^7.4|^8.0", + "symfony/console": "^5.3|^6.0", + "symfony/finder": "^5.3|^6.0" + }, + "require-dev": { + "mockery/mockery": "^1.3", + "orchestra/testbench": "^6.0|^7.0|^8.0", + "phpunit/phpunit": "^9.0" + }, + "bin": [ + "bin/blade-icons-generate" + ], + "type": "library", + "extra": { + "laravel": { + "providers": [ + "BladeUI\\Icons\\BladeIconsServiceProvider" + ] + } + }, + "autoload": { + "files": [ + "src/helpers.php" + ], + "psr-4": { + "BladeUI\\Icons\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Dries Vints", + "homepage": "https://driesvints.com" + } + ], + "description": "A package to easily make use of icons in your Laravel Blade views.", + "homepage": "https://github.com/blade-ui-kit/blade-icons", + "keywords": [ + "blade", + "icons", + "laravel", + "svg" + ], + "support": { + "issues": "https://github.com/blade-ui-kit/blade-icons/issues", + "source": "https://github.com/blade-ui-kit/blade-icons" + }, + "funding": [ + { + "url": "https://github.com/sponsors/driesvints", + "type": "github" + }, + { + "url": "https://www.paypal.com/paypalme/driesvints", + "type": "paypal" + } + ], + "time": "2023-10-18T10:50:13+00:00" + }, { "name": "brick/math", "version": "0.11.0", @@ -618,6 +768,67 @@ }, "time": "2023-08-25T16:18:39+00:00" }, + { + "name": "davidhsianturi/blade-bootstrap-icons", + "version": "v1.4.0", + "source": { + "type": "git", + "url": "https://github.com/davidhsianturi/blade-bootstrap-icons.git", + "reference": "255040a0058683dd5a0fd36dfa0857a91a95137f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/davidhsianturi/blade-bootstrap-icons/zipball/255040a0058683dd5a0fd36dfa0857a91a95137f", + "reference": "255040a0058683dd5a0fd36dfa0857a91a95137f", + "shasum": "" + }, + "require": { + "blade-ui-kit/blade-icons": "^1.0", + "illuminate/support": "^8.0|^9.0|^10.0", + "php": "^7.4|^8.0" + }, + "require-dev": { + "orchestra/testbench": "^6.0|^7.0|^8.0", + "phpunit/phpunit": "^9.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Davidhsianturi\\BladeBootstrapIcons\\BladeBootstrapIconsServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Davidhsianturi\\BladeBootstrapIcons\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "David H. Sianturi", + "email": "davidhsianturi@gmail.com", + "homepage": "https://davidhsianturi.com", + "role": "Developer" + } + ], + "description": "A package to easily make use of Bootstrap Icons in your Laravel Blade views.", + "homepage": "https://github.com/davidhsianturi/blade-bootstrap-icons", + "keywords": [ + "Bootstrap Icons", + "blade", + "laravel" + ], + "support": { + "issues": "https://github.com/davidhsianturi/blade-bootstrap-icons/issues", + "source": "https://github.com/davidhsianturi/blade-bootstrap-icons/tree/v1.4.0" + }, + "time": "2023-03-17T14:49:47+00:00" + }, { "name": "dflydev/dot-access-data", "version": "v3.0.2", @@ -1533,6 +1744,67 @@ ], "time": "2023-12-03T19:50:20+00:00" }, + { + "name": "khatabwedaa/blade-css-icons", + "version": "1.3.0", + "source": { + "type": "git", + "url": "https://github.com/khatabwedaa/blade-css-icons.git", + "reference": "a022e9a0057d9ce4f99728647fb139808c6134d8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/khatabwedaa/blade-css-icons/zipball/a022e9a0057d9ce4f99728647fb139808c6134d8", + "reference": "a022e9a0057d9ce4f99728647fb139808c6134d8", + "shasum": "" + }, + "require": { + "blade-ui-kit/blade-icons": "^1.1", + "illuminate/support": "^9.0|^10", + "php": "^8.0" + }, + "require-dev": { + "orchestra/testbench": "^7.0|^8.0", + "phpunit/phpunit": "^9.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Khatabwedaa\\BladeCssIcons\\BladeCssIconsServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Khatabwedaa\\BladeCssIcons\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Khatab Wedaa", + "email": "khatabwedaa@gmail.com", + "homepage": "https://twitter.com/khatabwedaa", + "role": "Developer" + } + ], + "description": "A package to easily make use of Css.gg in your Laravel Blade views.", + "homepage": "https://github.com/khatabwedaa/blade-css-icons", + "keywords": [ + "Css.gg", + "blade", + "laravel" + ], + "support": { + "issues": "https://github.com/khatabwedaa/blade-css-icons/issues", + "source": "https://github.com/khatabwedaa/blade-css-icons/tree/1.3.0" + }, + "time": "2023-02-04T14:04:11+00:00" + }, { "name": "laminas/laminas-code", "version": "4.13.0", @@ -3382,6 +3654,68 @@ ], "time": "2023-09-03T08:22:57+00:00" }, + { + "name": "owenvoke/blade-fontawesome", + "version": "v2.5.1", + "source": { + "type": "git", + "url": "https://github.com/owenvoke/blade-fontawesome.git", + "reference": "b3eac80b0f2f1b70083d4acea0da49350f88856e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/owenvoke/blade-fontawesome/zipball/b3eac80b0f2f1b70083d4acea0da49350f88856e", + "reference": "b3eac80b0f2f1b70083d4acea0da49350f88856e", + "shasum": "" + }, + "require": { + "blade-ui-kit/blade-icons": "^1.5", + "illuminate/support": "^10.34", + "php": "^8.1", + "thecodingmachine/safe": "^2.5" + }, + "require-dev": { + "laravel/pint": "^1.13", + "orchestra/testbench": "^8.12", + "pestphp/pest": "^2.26", + "phpstan/phpstan": "^1.10", + "symfony/var-dumper": "^6.3", + "thecodingmachine/phpstan-safe-rule": "^1.2" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "OwenVoke\\BladeFontAwesome\\BladeFontAwesomeServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "OwenVoke\\BladeFontAwesome\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A package to easily make use of Font Awesome in your Laravel Blade views", + "support": { + "issues": "https://github.com/owenvoke/blade-fontawesome/issues", + "source": "https://github.com/owenvoke/blade-fontawesome/tree/v2.5.1" + }, + "funding": [ + { + "url": "https://ecologi.com/owenvoke?gift-trees", + "type": "custom" + }, + { + "url": "https://github.com/owenvoke", + "type": "github" + } + ], + "time": "2023-12-12T09:07:03+00:00" + }, { "name": "paragonie/constant_time_encoding", "version": "v2.6.3", @@ -6710,6 +7044,145 @@ ], "time": "2023-12-28T19:16:56+00:00" }, + { + "name": "thecodingmachine/safe", + "version": "v2.5.0", + "source": { + "type": "git", + "url": "https://github.com/thecodingmachine/safe.git", + "reference": "3115ecd6b4391662b4931daac4eba6b07a2ac1f0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thecodingmachine/safe/zipball/3115ecd6b4391662b4931daac4eba6b07a2ac1f0", + "reference": "3115ecd6b4391662b4931daac4eba6b07a2ac1f0", + "shasum": "" + }, + "require": { + "php": "^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.5", + "phpunit/phpunit": "^9.5", + "squizlabs/php_codesniffer": "^3.2", + "thecodingmachine/phpstan-strict-rules": "^1.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.2.x-dev" + } + }, + "autoload": { + "files": [ + "deprecated/apc.php", + "deprecated/array.php", + "deprecated/datetime.php", + "deprecated/libevent.php", + "deprecated/misc.php", + "deprecated/password.php", + "deprecated/mssql.php", + "deprecated/stats.php", + "deprecated/strings.php", + "lib/special_cases.php", + "deprecated/mysqli.php", + "generated/apache.php", + "generated/apcu.php", + "generated/array.php", + "generated/bzip2.php", + "generated/calendar.php", + "generated/classobj.php", + "generated/com.php", + "generated/cubrid.php", + "generated/curl.php", + "generated/datetime.php", + "generated/dir.php", + "generated/eio.php", + "generated/errorfunc.php", + "generated/exec.php", + "generated/fileinfo.php", + "generated/filesystem.php", + "generated/filter.php", + "generated/fpm.php", + "generated/ftp.php", + "generated/funchand.php", + "generated/gettext.php", + "generated/gmp.php", + "generated/gnupg.php", + "generated/hash.php", + "generated/ibase.php", + "generated/ibmDb2.php", + "generated/iconv.php", + "generated/image.php", + "generated/imap.php", + "generated/info.php", + "generated/inotify.php", + "generated/json.php", + "generated/ldap.php", + "generated/libxml.php", + "generated/lzf.php", + "generated/mailparse.php", + "generated/mbstring.php", + "generated/misc.php", + "generated/mysql.php", + "generated/network.php", + "generated/oci8.php", + "generated/opcache.php", + "generated/openssl.php", + "generated/outcontrol.php", + "generated/pcntl.php", + "generated/pcre.php", + "generated/pgsql.php", + "generated/posix.php", + "generated/ps.php", + "generated/pspell.php", + "generated/readline.php", + "generated/rpminfo.php", + "generated/rrd.php", + "generated/sem.php", + "generated/session.php", + "generated/shmop.php", + "generated/sockets.php", + "generated/sodium.php", + "generated/solr.php", + "generated/spl.php", + "generated/sqlsrv.php", + "generated/ssdeep.php", + "generated/ssh2.php", + "generated/stream.php", + "generated/strings.php", + "generated/swoole.php", + "generated/uodbc.php", + "generated/uopz.php", + "generated/url.php", + "generated/var.php", + "generated/xdiff.php", + "generated/xml.php", + "generated/xmlrpc.php", + "generated/yaml.php", + "generated/yaz.php", + "generated/zip.php", + "generated/zlib.php" + ], + "classmap": [ + "lib/DateTime.php", + "lib/DateTimeImmutable.php", + "lib/Exceptions/", + "deprecated/Exceptions/", + "generated/Exceptions/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHP core functions that throw exceptions instead of returning FALSE on error", + "support": { + "issues": "https://github.com/thecodingmachine/safe/issues", + "source": "https://github.com/thecodingmachine/safe/tree/v2.5.0" + }, + "time": "2023-04-05T11:54:14+00:00" + }, { "name": "tijsverkoyen/css-to-inline-styles", "version": "v2.2.7", diff --git a/config/core.php b/config/core.php index 1ac8eeab..d2dfd118 100755 --- a/config/core.php +++ b/config/core.php @@ -13,6 +13,7 @@ use App\NotificationChannels\Discord; use App\NotificationChannels\Email; use App\NotificationChannels\Slack; +use App\NotificationChannels\Telegram; use App\ServerProviders\AWS; use App\ServerProviders\DigitalOcean; use App\ServerProviders\Hetzner; @@ -343,11 +344,13 @@ \App\Enums\NotificationChannel::SLACK, \App\Enums\NotificationChannel::DISCORD, \App\Enums\NotificationChannel::EMAIL, + \App\Enums\NotificationChannel::TELEGRAM, ], 'notification_channels_providers_class' => [ \App\Enums\NotificationChannel::SLACK => Slack::class, \App\Enums\NotificationChannel::DISCORD => Discord::class, \App\Enums\NotificationChannel::EMAIL => Email::class, + \App\Enums\NotificationChannel::TELEGRAM => Telegram::class, ], /* diff --git a/install/install.sh b/install/install.sh index e7b3f544..14ebcb6b 100644 --- a/install/install.sh +++ b/install/install.sh @@ -233,6 +233,11 @@ chmod +x /home/${V_USERNAME}/${V_DOMAIN}/update.sh # cleanup chown -R ${V_USERNAME}:${V_USERNAME} /home/${V_USERNAME} +# cache +php artisan config:cache +php artisan icons:cache + +# print info echo "🎉 Congratulations!" echo "✅ SSH User: ${V_USERNAME}" echo "✅ SSH Password: ${V_PASSWORD}" diff --git a/public/build/assets/app-8b808e33.css b/public/build/assets/app-8b808e33.css new file mode 100644 index 00000000..6aaf4107 --- /dev/null +++ b/public/build/assets/app-8b808e33.css @@ -0,0 +1 @@ +.toast-title{font-weight:700}.toast-message{-ms-word-wrap:break-word;word-wrap:break-word}.toast-message a,.toast-message label{color:#fff}.toast-message a:hover{color:#ccc;text-decoration:none}.toast-close-button{position:relative;right:-.3em;top:-.3em;float:right;font-size:20px;font-weight:700;color:#fff;-webkit-text-shadow:0 1px 0 #ffffff;text-shadow:0 1px 0 #ffffff;opacity:.8;-ms-filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=80);filter:alpha(opacity=80);line-height:1}.toast-close-button:hover,.toast-close-button:focus{color:#000;text-decoration:none;cursor:pointer;opacity:.4;-ms-filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=40);filter:alpha(opacity=40)}.rtl .toast-close-button{left:-.3em;float:left;right:.3em}button.toast-close-button{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.toast-top-center{top:0;right:0;width:100%}.toast-bottom-center{bottom:0;right:0;width:100%}.toast-top-full-width{top:0;right:0;width:100%}.toast-bottom-full-width{bottom:0;right:0;width:100%}.toast-top-left{top:12px;left:12px}.toast-top-right{top:12px;right:12px}.toast-bottom-right{right:12px;bottom:12px}.toast-bottom-left{bottom:12px;left:12px}#toast-container{position:fixed;z-index:999999;pointer-events:none}#toast-container *{box-sizing:border-box}#toast-container>div{border-radius:.5rem;position:relative;pointer-events:auto;overflow:hidden;margin:0 0 6px;padding:15px 15px 15px 50px;width:300px;background-position:15px center;background-repeat:no-repeat;color:#fff}#toast-container>div.rtl{direction:rtl;padding:15px 50px 15px 15px;background-position:right 15px center}#toast-container>div:hover{cursor:pointer;--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}#toast-container>.toast-info{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGwSURBVEhLtZa9SgNBEMc9sUxxRcoUKSzSWIhXpFMhhYWFhaBg4yPYiWCXZxBLERsLRS3EQkEfwCKdjWJAwSKCgoKCcudv4O5YLrt7EzgXhiU3/4+b2ckmwVjJSpKkQ6wAi4gwhT+z3wRBcEz0yjSseUTrcRyfsHsXmD0AmbHOC9Ii8VImnuXBPglHpQ5wwSVM7sNnTG7Za4JwDdCjxyAiH3nyA2mtaTJufiDZ5dCaqlItILh1NHatfN5skvjx9Z38m69CgzuXmZgVrPIGE763Jx9qKsRozWYw6xOHdER+nn2KkO+Bb+UV5CBN6WC6QtBgbRVozrahAbmm6HtUsgtPC19tFdxXZYBOfkbmFJ1VaHA1VAHjd0pp70oTZzvR+EVrx2Ygfdsq6eu55BHYR8hlcki+n+kERUFG8BrA0BwjeAv2M8WLQBtcy+SD6fNsmnB3AlBLrgTtVW1c2QN4bVWLATaIS60J2Du5y1TiJgjSBvFVZgTmwCU+dAZFoPxGEEs8nyHC9Bwe2GvEJv2WXZb0vjdyFT4Cxk3e/kIqlOGoVLwwPevpYHT+00T+hWwXDf4AJAOUqWcDhbwAAAAASUVORK5CYII=)!important}#toast-container>.toast-error{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHOSURBVEhLrZa/SgNBEMZzh0WKCClSCKaIYOED+AAKeQQLG8HWztLCImBrYadgIdY+gIKNYkBFSwu7CAoqCgkkoGBI/E28PdbLZmeDLgzZzcx83/zZ2SSXC1j9fr+I1Hq93g2yxH4iwM1vkoBWAdxCmpzTxfkN2RcyZNaHFIkSo10+8kgxkXIURV5HGxTmFuc75B2RfQkpxHG8aAgaAFa0tAHqYFfQ7Iwe2yhODk8+J4C7yAoRTWI3w/4klGRgR4lO7Rpn9+gvMyWp+uxFh8+H+ARlgN1nJuJuQAYvNkEnwGFck18Er4q3egEc/oO+mhLdKgRyhdNFiacC0rlOCbhNVz4H9FnAYgDBvU3QIioZlJFLJtsoHYRDfiZoUyIxqCtRpVlANq0EU4dApjrtgezPFad5S19Wgjkc0hNVnuF4HjVA6C7QrSIbylB+oZe3aHgBsqlNqKYH48jXyJKMuAbiyVJ8KzaB3eRc0pg9VwQ4niFryI68qiOi3AbjwdsfnAtk0bCjTLJKr6mrD9g8iq/S/B81hguOMlQTnVyG40wAcjnmgsCNESDrjme7wfftP4P7SP4N3CJZdvzoNyGq2c/HWOXJGsvVg+RA/k2MC/wN6I2YA2Pt8GkAAAAASUVORK5CYII=)!important}#toast-container>.toast-success{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADsSURBVEhLY2AYBfQMgf///3P8+/evAIgvA/FsIF+BavYDDWMBGroaSMMBiE8VC7AZDrIFaMFnii3AZTjUgsUUWUDA8OdAH6iQbQEhw4HyGsPEcKBXBIC4ARhex4G4BsjmweU1soIFaGg/WtoFZRIZdEvIMhxkCCjXIVsATV6gFGACs4Rsw0EGgIIH3QJYJgHSARQZDrWAB+jawzgs+Q2UO49D7jnRSRGoEFRILcdmEMWGI0cm0JJ2QpYA1RDvcmzJEWhABhD/pqrL0S0CWuABKgnRki9lLseS7g2AlqwHWQSKH4oKLrILpRGhEQCw2LiRUIa4lwAAAABJRU5ErkJggg==)!important}#toast-container>.toast-warning{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGYSURBVEhL5ZSvTsNQFMbXZGICMYGYmJhAQIJAICYQPAACiSDB8AiICQQJT4CqQEwgJvYASAQCiZiYmJhAIBATCARJy+9rTsldd8sKu1M0+dLb057v6/lbq/2rK0mS/TRNj9cWNAKPYIJII7gIxCcQ51cvqID+GIEX8ASG4B1bK5gIZFeQfoJdEXOfgX4QAQg7kH2A65yQ87lyxb27sggkAzAuFhbbg1K2kgCkB1bVwyIR9m2L7PRPIhDUIXgGtyKw575yz3lTNs6X4JXnjV+LKM/m3MydnTbtOKIjtz6VhCBq4vSm3ncdrD2lk0VgUXSVKjVDJXJzijW1RQdsU7F77He8u68koNZTz8Oz5yGa6J3H3lZ0xYgXBK2QymlWWA+RWnYhskLBv2vmE+hBMCtbA7KX5drWyRT/2JsqZ2IvfB9Y4bWDNMFbJRFmC9E74SoS0CqulwjkC0+5bpcV1CZ8NMej4pjy0U+doDQsGyo1hzVJttIjhQ7GnBtRFN1UarUlH8F3xict+HY07rEzoUGPlWcjRFRr4/gChZgc3ZL2d8oAAAAASUVORK5CYII=)!important}#toast-container.toast-top-center>div,#toast-container.toast-bottom-center>div{width:300px;margin-left:auto;margin-right:auto}#toast-container.toast-top-full-width>div,#toast-container.toast-bottom-full-width>div{width:96%;margin-left:auto;margin-right:auto}.toast{background-color:#030303}.toast-success{--tw-bg-opacity: 1;background-color:rgb(34 197 94 / var(--tw-bg-opacity))}.toast-error{--tw-bg-opacity: 1;background-color:rgb(239 68 68 / var(--tw-bg-opacity))}.toast-info{--tw-bg-opacity: 1;background-color:rgb(99 102 241 / var(--tw-bg-opacity))}.toast-warning{--tw-bg-opacity: 1;background-color:rgb(234 179 8 / var(--tw-bg-opacity))}.toast-progress{position:absolute;left:0;bottom:0;height:4px;background-color:#000;opacity:.4;-ms-filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=40);filter:alpha(opacity=40)}@media all and (max-width: 240px){#toast-container>div{padding:8px 8px 8px 50px;width:11em}#toast-container>div.rtl{padding:8px 50px 8px 8px}#toast-container .toast-close-button{right:-.2em;top:-.2em}#toast-container .rtl .toast-close-button{left:-.2em;right:.2em}}@media all and (min-width: 241px) and (max-width: 480px){#toast-container>div{padding:8px 8px 8px 50px;width:18em}#toast-container>div.rtl{padding:8px 50px 8px 8px}#toast-container .toast-close-button{right:-.2em;top:-.2em}#toast-container .rtl .toast-close-button{left:-.2em;right:.2em}}@media all and (min-width: 481px) and (max-width: 768px){#toast-container>div{padding:15px 15px 15px 50px;width:25em}#toast-container>div.rtl{padding:15px 50px 15px 15px}}/*! tailwindcss v3.3.1 | MIT License | https://tailwindcss.com*/*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e2e8f0}:before,:after{--tw-content: ""}html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:Figtree,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,[type=button],[type=reset],[type=submit]{-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#94a3b8}input::placeholder,textarea::placeholder{opacity:1;color:#94a3b8}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}[type=text],[type=email],[type=url],[type=password],[type=number],[type=date],[type=datetime-local],[type=month],[type=search],[type=tel],[type=time],[type=week],[multiple],textarea,select{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border-color:#64748b;border-width:1px;border-radius:0;padding:.5rem .75rem;font-size:1rem;line-height:1.5rem;--tw-shadow: 0 0 #0000}[type=text]:focus,[type=email]:focus,[type=url]:focus,[type=password]:focus,[type=number]:focus,[type=date]:focus,[type=datetime-local]:focus,[type=month]:focus,[type=search]:focus,[type=tel]:focus,[type=time]:focus,[type=week]:focus,[multiple]:focus,textarea:focus,select:focus{outline:2px solid transparent;outline-offset:2px;--tw-ring-inset: var(--tw-empty, );--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: #2563eb;--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);border-color:#2563eb}input::-moz-placeholder,textarea::-moz-placeholder{color:#64748b;opacity:1}input::placeholder,textarea::placeholder{color:#64748b;opacity:1}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-date-and-time-value{min-height:1.5em}::-webkit-datetime-edit,::-webkit-datetime-edit-year-field,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute-field,::-webkit-datetime-edit-second-field,::-webkit-datetime-edit-millisecond-field,::-webkit-datetime-edit-meridiem-field{padding-top:0;padding-bottom:0}select{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%2364748b' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e");background-position:right .5rem center;background-repeat:no-repeat;background-size:1.5em 1.5em;padding-right:2.5rem;-webkit-print-color-adjust:exact;print-color-adjust:exact}[multiple]{background-image:initial;background-position:initial;background-repeat:unset;background-size:initial;padding-right:.75rem;-webkit-print-color-adjust:unset;print-color-adjust:unset}[type=checkbox],[type=radio]{-webkit-appearance:none;-moz-appearance:none;appearance:none;padding:0;-webkit-print-color-adjust:exact;print-color-adjust:exact;display:inline-block;vertical-align:middle;background-origin:border-box;-webkit-user-select:none;-moz-user-select:none;user-select:none;flex-shrink:0;height:1rem;width:1rem;color:#2563eb;background-color:#fff;border-color:#64748b;border-width:1px;--tw-shadow: 0 0 #0000}[type=checkbox]{border-radius:0}[type=radio]{border-radius:100%}[type=checkbox]:focus,[type=radio]:focus{outline:2px solid transparent;outline-offset:2px;--tw-ring-inset: var(--tw-empty, );--tw-ring-offset-width: 2px;--tw-ring-offset-color: #fff;--tw-ring-color: #2563eb;--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}[type=checkbox]:checked,[type=radio]:checked{border-color:transparent;background-color:currentColor;background-size:100% 100%;background-position:center;background-repeat:no-repeat}[type=checkbox]:checked{background-image:url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e")}[type=radio]:checked{background-image:url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3ccircle cx='8' cy='8' r='3'/%3e%3c/svg%3e")}[type=checkbox]:checked:hover,[type=checkbox]:checked:focus,[type=radio]:checked:hover,[type=radio]:checked:focus{border-color:transparent;background-color:currentColor}[type=checkbox]:indeterminate{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 16'%3e%3cpath stroke='white' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8h8'/%3e%3c/svg%3e");border-color:transparent;background-color:currentColor;background-size:100% 100%;background-position:center;background-repeat:no-repeat}[type=checkbox]:indeterminate:hover,[type=checkbox]:indeterminate:focus{border-color:transparent;background-color:currentColor}[type=file]{background:unset;border-color:inherit;border-width:0;border-radius:0;padding:0;font-size:unset;line-height:inherit}[type=file]:focus{outline:1px solid ButtonText;outline:1px auto -webkit-focus-ring-color}*,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.container{width:100%}@media (min-width: 640px){.container{max-width:640px}}@media (min-width: 768px){.container{max-width:768px}}@media (min-width: 1024px){.container{max-width:1024px}}@media (min-width: 1280px){.container{max-width:1280px}}@media (min-width: 1536px){.container{max-width:1536px}}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.inset-0{inset:0px}.inset-y-0{top:0px;bottom:0px}.left-0{left:0px}.right-0{right:0px}.top-0{top:0px}.top-1{top:.25rem}.z-0{z-index:0}.z-10{z-index:10}.z-50{z-index:50}.float-right{float:right}.mx-5{margin-left:1.25rem;margin-right:1.25rem}.mx-auto{margin-left:auto;margin-right:auto}.-ml-px{margin-left:-1px}.-mr-0{margin-right:-0px}.-mr-0\.5{margin-right:-.125rem}.mb-1{margin-bottom:.25rem}.mb-10{margin-bottom:2.5rem}.mb-2{margin-bottom:.5rem}.mb-4{margin-bottom:1rem}.mb-5{margin-bottom:1.25rem}.mb-6{margin-bottom:1.5rem}.ml-1{margin-left:.25rem}.ml-2{margin-left:.5rem}.ml-3{margin-left:.75rem}.mr-1{margin-right:.25rem}.mr-2{margin-right:.5rem}.mr-3{margin-right:.75rem}.mt-1{margin-top:.25rem}.mt-10{margin-top:2.5rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.mt-5{margin-top:1.25rem}.mt-6{margin-top:1.5rem}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.hidden{display:none}.h-10{height:2.5rem}.h-16{height:4rem}.h-20{height:5rem}.h-4{height:1rem}.h-48{height:12rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-7{height:1.75rem}.h-8{height:2rem}.h-9{height:2.25rem}.h-96{height:24rem}.max-h-\[350px\]{max-height:350px}.min-h-screen{min-height:100vh}.w-1{width:.25rem}.w-10{width:2.5rem}.w-4{width:1rem}.w-48{width:12rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-64{width:16rem}.w-7{width:1.75rem}.w-8{width:2rem}.w-9{width:2.25rem}.w-full{width:100%}.w-max{width:-moz-max-content;width:max-content}.min-w-full{min-width:100%}.min-w-max{min-width:-moz-max-content;min-width:max-content}.max-w-7xl{max-width:80rem}.max-w-full{max-width:100%}.flex-1{flex:1 1 0%}.flex-none{flex:none}.flex-grow{flex-grow:1}.origin-top{transform-origin:top}.origin-top-left{transform-origin:top left}.origin-top-right{transform-origin:top right}.translate-y-0{--tw-translate-y: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-y-4{--tw-translate-y: 1rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.scale-100{--tw-scale-x: 1;--tw-scale-y: 1;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.scale-95{--tw-scale-x: .95;--tw-scale-y: .95;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.cursor-default{cursor:default}.cursor-pointer{cursor:pointer}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.grid-cols-6{grid-template-columns:repeat(6,minmax(0,1fr))}.flex-col{flex-direction:column}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.justify-items-center{justify-items:center}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-5{gap:1.25rem}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem * var(--tw-space-y-reverse))}.space-y-10>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(2.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(2.5rem * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.75rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem * var(--tw-space-y-reverse))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem * var(--tw-space-y-reverse))}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.overflow-y-hidden{overflow-y:hidden}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-line{white-space:pre-line}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-sm{border-radius:.125rem}.rounded-b-md{border-bottom-right-radius:.375rem;border-bottom-left-radius:.375rem}.rounded-l-md{border-top-left-radius:.375rem;border-bottom-left-radius:.375rem}.rounded-r-md{border-top-right-radius:.375rem;border-bottom-right-radius:.375rem}.rounded-t-md{border-top-left-radius:.375rem;border-top-right-radius:.375rem}.rounded-tr-md{border-top-right-radius:.375rem}.border{border-width:1px}.border-2{border-width:2px}.border-b{border-bottom-width:1px}.border-b-2{border-bottom-width:2px}.border-l{border-left-width:1px}.border-l-4{border-left-width:4px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-gray-100{--tw-border-opacity: 1;border-color:rgb(241 245 249 / var(--tw-border-opacity))}.border-gray-200{--tw-border-opacity: 1;border-color:rgb(226 232 240 / var(--tw-border-opacity))}.border-gray-300{--tw-border-opacity: 1;border-color:rgb(203 213 225 / var(--tw-border-opacity))}.border-primary-200{--tw-border-opacity: 1;border-color:rgb(199 210 254 / var(--tw-border-opacity))}.border-primary-400{--tw-border-opacity: 1;border-color:rgb(129 140 248 / var(--tw-border-opacity))}.border-primary-600{--tw-border-opacity: 1;border-color:rgb(79 70 229 / var(--tw-border-opacity))}.border-transparent{border-color:transparent}.border-yellow-500{--tw-border-opacity: 1;border-color:rgb(234 179 8 / var(--tw-border-opacity))}.border-t-transparent{border-top-color:transparent}.bg-gray-100{--tw-bg-opacity: 1;background-color:rgb(241 245 249 / var(--tw-bg-opacity))}.bg-gray-200{--tw-bg-opacity: 1;background-color:rgb(226 232 240 / var(--tw-bg-opacity))}.bg-gray-50{--tw-bg-opacity: 1;background-color:rgb(248 250 252 / var(--tw-bg-opacity))}.bg-gray-500{--tw-bg-opacity: 1;background-color:rgb(100 116 139 / var(--tw-bg-opacity))}.bg-gray-800{--tw-bg-opacity: 1;background-color:rgb(30 41 59 / var(--tw-bg-opacity))}.bg-gray-900{--tw-bg-opacity: 1;background-color:rgb(15 23 42 / var(--tw-bg-opacity))}.bg-green-50{--tw-bg-opacity: 1;background-color:rgb(240 253 244 / var(--tw-bg-opacity))}.bg-primary-200{--tw-bg-opacity: 1;background-color:rgb(199 210 254 / var(--tw-bg-opacity))}.bg-primary-50{--tw-bg-opacity: 1;background-color:rgb(238 242 255 / var(--tw-bg-opacity))}.bg-primary-500{--tw-bg-opacity: 1;background-color:rgb(99 102 241 / var(--tw-bg-opacity))}.bg-primary-600{--tw-bg-opacity: 1;background-color:rgb(79 70 229 / var(--tw-bg-opacity))}.bg-red-50{--tw-bg-opacity: 1;background-color:rgb(254 242 242 / var(--tw-bg-opacity))}.bg-red-600{--tw-bg-opacity: 1;background-color:rgb(220 38 38 / var(--tw-bg-opacity))}.bg-white{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity))}.bg-yellow-100{--tw-bg-opacity: 1;background-color:rgb(254 249 195 / var(--tw-bg-opacity))}.bg-yellow-50{--tw-bg-opacity: 1;background-color:rgb(254 252 232 / var(--tw-bg-opacity))}.p-1{padding:.25rem}.p-2{padding:.5rem}.p-3{padding:.75rem}.p-5{padding:1.25rem}.p-6{padding:1.5rem}.p-7{padding:1.75rem}.px-1{padding-left:.25rem;padding-right:.25rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.px-8{padding-left:2rem;padding-right:2rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-12{padding-top:3rem;padding-bottom:3rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-5{padding-top:1.25rem;padding-bottom:1.25rem}.py-6{padding-top:1.5rem;padding-bottom:1.5rem}.pb-1{padding-bottom:.25rem}.pb-2{padding-bottom:.5rem}.pl-3{padding-left:.75rem}.pr-10{padding-right:2.5rem}.pr-2{padding-right:.5rem}.pr-3{padding-right:.75rem}.pr-4{padding-right:1rem}.pt-1{padding-top:.25rem}.pt-3{padding-top:.75rem}.pt-6{padding-top:1.5rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.align-middle{vertical-align:middle}.font-sans{font-family:Figtree,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji"}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-extrabold{font-weight:800}.font-medium{font-weight:500}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.lowercase{text-transform:lowercase}.capitalize{text-transform:capitalize}.leading-4{line-height:1rem}.leading-5{line-height:1.25rem}.tracking-wider{letter-spacing:.05em}.text-black{--tw-text-opacity: 1;color:rgb(0 0 0 / var(--tw-text-opacity))}.text-gray-100{--tw-text-opacity: 1;color:rgb(241 245 249 / var(--tw-text-opacity))}.text-gray-300{--tw-text-opacity: 1;color:rgb(203 213 225 / var(--tw-text-opacity))}.text-gray-400{--tw-text-opacity: 1;color:rgb(148 163 184 / var(--tw-text-opacity))}.text-gray-50{--tw-text-opacity: 1;color:rgb(248 250 252 / var(--tw-text-opacity))}.text-gray-500{--tw-text-opacity: 1;color:rgb(100 116 139 / var(--tw-text-opacity))}.text-gray-600{--tw-text-opacity: 1;color:rgb(71 85 105 / var(--tw-text-opacity))}.text-gray-700{--tw-text-opacity: 1;color:rgb(51 65 85 / var(--tw-text-opacity))}.text-gray-800{--tw-text-opacity: 1;color:rgb(30 41 59 / var(--tw-text-opacity))}.text-gray-900{--tw-text-opacity: 1;color:rgb(15 23 42 / var(--tw-text-opacity))}.text-green-500{--tw-text-opacity: 1;color:rgb(34 197 94 / var(--tw-text-opacity))}.text-green-600{--tw-text-opacity: 1;color:rgb(22 163 74 / var(--tw-text-opacity))}.text-indigo-600{--tw-text-opacity: 1;color:rgb(79 70 229 / var(--tw-text-opacity))}.text-primary-500{--tw-text-opacity: 1;color:rgb(99 102 241 / var(--tw-text-opacity))}.text-primary-600{--tw-text-opacity: 1;color:rgb(79 70 229 / var(--tw-text-opacity))}.text-primary-700{--tw-text-opacity: 1;color:rgb(67 56 202 / var(--tw-text-opacity))}.text-red-500{--tw-text-opacity: 1;color:rgb(239 68 68 / var(--tw-text-opacity))}.text-red-600{--tw-text-opacity: 1;color:rgb(220 38 38 / var(--tw-text-opacity))}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity))}.text-yellow-500{--tw-text-opacity: 1;color:rgb(234 179 8 / var(--tw-text-opacity))}.text-yellow-700{--tw-text-opacity: 1;color:rgb(161 98 7 / var(--tw-text-opacity))}.underline{text-decoration-line:underline}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.opacity-0{opacity:0}.opacity-100{opacity:1}.opacity-25{opacity:.25}.opacity-75{opacity:.75}.shadow-lg{--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-md{--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-none{--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / .05);--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-xl{--tw-shadow: 0 20px 25px -5px rgb(0 0 0 / .1), 0 8px 10px -6px rgb(0 0 0 / .1);--tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.outline-0{outline-width:0px}.ring-1{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-black{--tw-ring-opacity: 1;--tw-ring-color: rgb(0 0 0 / var(--tw-ring-opacity))}.ring-gray-300{--tw-ring-opacity: 1;--tw-ring-color: rgb(203 213 225 / var(--tw-ring-opacity))}.ring-opacity-5{--tw-ring-opacity: .05}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-100{transition-duration:.1s}.duration-150{transition-duration:.15s}.duration-200{transition-duration:.2s}.duration-300{transition-duration:.3s}.duration-75{transition-duration:75ms}.ease-in{transition-timing-function:cubic-bezier(.4,0,1,1)}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}[x-cloak]{display:none!important}.hover\:border-gray-300:hover{--tw-border-opacity: 1;border-color:rgb(203 213 225 / var(--tw-border-opacity))}.hover\:bg-gray-100:hover{--tw-bg-opacity: 1;background-color:rgb(241 245 249 / var(--tw-bg-opacity))}.hover\:bg-gray-50:hover{--tw-bg-opacity: 1;background-color:rgb(248 250 252 / var(--tw-bg-opacity))}.hover\:bg-gray-900:hover{--tw-bg-opacity: 1;background-color:rgb(15 23 42 / var(--tw-bg-opacity))}.hover\:bg-primary-600:hover{--tw-bg-opacity: 1;background-color:rgb(79 70 229 / var(--tw-bg-opacity))}.hover\:bg-primary-700:hover{--tw-bg-opacity: 1;background-color:rgb(67 56 202 / var(--tw-bg-opacity))}.hover\:bg-red-500:hover{--tw-bg-opacity: 1;background-color:rgb(239 68 68 / var(--tw-bg-opacity))}.hover\:text-gray-400:hover{--tw-text-opacity: 1;color:rgb(148 163 184 / var(--tw-text-opacity))}.hover\:text-gray-500:hover{--tw-text-opacity: 1;color:rgb(100 116 139 / var(--tw-text-opacity))}.hover\:text-gray-700:hover{--tw-text-opacity: 1;color:rgb(51 65 85 / var(--tw-text-opacity))}.hover\:text-gray-800:hover{--tw-text-opacity: 1;color:rgb(30 41 59 / var(--tw-text-opacity))}.hover\:text-gray-900:hover{--tw-text-opacity: 1;color:rgb(15 23 42 / var(--tw-text-opacity))}.hover\:text-white:hover{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity))}.hover\:opacity-50:hover{opacity:.5}.focus\:z-10:focus{z-index:10}.focus\:border-blue-300:focus{--tw-border-opacity: 1;border-color:rgb(147 197 253 / var(--tw-border-opacity))}.focus\:border-gray-300:focus{--tw-border-opacity: 1;border-color:rgb(203 213 225 / var(--tw-border-opacity))}.focus\:border-primary-300:focus{--tw-border-opacity: 1;border-color:rgb(165 180 252 / var(--tw-border-opacity))}.focus\:border-primary-500:focus{--tw-border-opacity: 1;border-color:rgb(99 102 241 / var(--tw-border-opacity))}.focus\:border-primary-700:focus{--tw-border-opacity: 1;border-color:rgb(67 56 202 / var(--tw-border-opacity))}.focus\:border-red-700:focus{--tw-border-opacity: 1;border-color:rgb(185 28 28 / var(--tw-border-opacity))}.focus\:bg-gray-100:focus{--tw-bg-opacity: 1;background-color:rgb(241 245 249 / var(--tw-bg-opacity))}.focus\:bg-gray-50:focus{--tw-bg-opacity: 1;background-color:rgb(248 250 252 / var(--tw-bg-opacity))}.focus\:bg-primary-100:focus{--tw-bg-opacity: 1;background-color:rgb(224 231 255 / var(--tw-bg-opacity))}.focus\:text-gray-700:focus{--tw-text-opacity: 1;color:rgb(51 65 85 / var(--tw-text-opacity))}.focus\:text-gray-800:focus{--tw-text-opacity: 1;color:rgb(30 41 59 / var(--tw-text-opacity))}.focus\:text-primary-800:focus{--tw-text-opacity: 1;color:rgb(55 48 163 / var(--tw-text-opacity))}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring:focus{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus\:ring-1:focus{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus\:ring-2:focus{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus\:ring-gray-400:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(148 163 184 / var(--tw-ring-opacity))}.focus\:ring-gray-500:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(100 116 139 / var(--tw-ring-opacity))}.focus\:ring-gray-700:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(51 65 85 / var(--tw-ring-opacity))}.focus\:ring-indigo-500:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(99 102 241 / var(--tw-ring-opacity))}.focus\:ring-primary-200:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(199 210 254 / var(--tw-ring-opacity))}.focus\:ring-primary-500:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(99 102 241 / var(--tw-ring-opacity))}.focus\:ring-red-200:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(254 202 202 / var(--tw-ring-opacity))}.focus\:ring-opacity-50:focus{--tw-ring-opacity: .5}.focus\:ring-offset-2:focus{--tw-ring-offset-width: 2px}.active\:bg-gray-100:active{--tw-bg-opacity: 1;background-color:rgb(241 245 249 / var(--tw-bg-opacity))}.active\:bg-primary-700:active{--tw-bg-opacity: 1;background-color:rgb(67 56 202 / var(--tw-bg-opacity))}.active\:bg-red-600:active{--tw-bg-opacity: 1;background-color:rgb(220 38 38 / var(--tw-bg-opacity))}.active\:text-gray-500:active{--tw-text-opacity: 1;color:rgb(100 116 139 / var(--tw-text-opacity))}.active\:text-gray-700:active{--tw-text-opacity: 1;color:rgb(51 65 85 / var(--tw-text-opacity))}.disabled\:opacity-25:disabled{opacity:.25}:is(.dark .dark\:border-r-2){border-right-width:2px}:is(.dark .dark\:border-gray-500){--tw-border-opacity: 1;border-color:rgb(100 116 139 / var(--tw-border-opacity))}:is(.dark .dark\:border-gray-600){--tw-border-opacity: 1;border-color:rgb(71 85 105 / var(--tw-border-opacity))}:is(.dark .dark\:border-gray-700){--tw-border-opacity: 1;border-color:rgb(51 65 85 / var(--tw-border-opacity))}:is(.dark .dark\:border-gray-800){--tw-border-opacity: 1;border-color:rgb(30 41 59 / var(--tw-border-opacity))}:is(.dark .dark\:border-gray-900){--tw-border-opacity: 1;border-color:rgb(15 23 42 / var(--tw-border-opacity))}:is(.dark .dark\:border-primary-600){--tw-border-opacity: 1;border-color:rgb(79 70 229 / var(--tw-border-opacity))}:is(.dark .dark\:border-t-transparent){border-top-color:transparent}:is(.dark .dark\:border-opacity-20){--tw-border-opacity: .2}:is(.dark .dark\:bg-gray-500){--tw-bg-opacity: 1;background-color:rgb(100 116 139 / var(--tw-bg-opacity))}:is(.dark .dark\:bg-gray-700){--tw-bg-opacity: 1;background-color:rgb(51 65 85 / var(--tw-bg-opacity))}:is(.dark .dark\:bg-gray-800){--tw-bg-opacity: 1;background-color:rgb(30 41 59 / var(--tw-bg-opacity))}:is(.dark .dark\:bg-gray-800\/50){background-color:#1e293b80}:is(.dark .dark\:bg-gray-900){--tw-bg-opacity: 1;background-color:rgb(15 23 42 / var(--tw-bg-opacity))}:is(.dark .dark\:bg-green-500){--tw-bg-opacity: 1;background-color:rgb(34 197 94 / var(--tw-bg-opacity))}:is(.dark .dark\:bg-primary-500){--tw-bg-opacity: 1;background-color:rgb(99 102 241 / var(--tw-bg-opacity))}:is(.dark .dark\:bg-primary-900\/50){background-color:#312e8180}:is(.dark .dark\:bg-red-500){--tw-bg-opacity: 1;background-color:rgb(239 68 68 / var(--tw-bg-opacity))}:is(.dark .dark\:bg-yellow-500){--tw-bg-opacity: 1;background-color:rgb(234 179 8 / var(--tw-bg-opacity))}:is(.dark .dark\:bg-opacity-10){--tw-bg-opacity: .1}:is(.dark .dark\:bg-opacity-20){--tw-bg-opacity: .2}:is(.dark .dark\:bg-opacity-30){--tw-bg-opacity: .3}:is(.dark .dark\:bg-opacity-70){--tw-bg-opacity: .7}:is(.dark .dark\:text-gray-100){--tw-text-opacity: 1;color:rgb(241 245 249 / var(--tw-text-opacity))}:is(.dark .dark\:text-gray-200){--tw-text-opacity: 1;color:rgb(226 232 240 / var(--tw-text-opacity))}:is(.dark .dark\:text-gray-300){--tw-text-opacity: 1;color:rgb(203 213 225 / var(--tw-text-opacity))}:is(.dark .dark\:text-gray-400){--tw-text-opacity: 1;color:rgb(148 163 184 / var(--tw-text-opacity))}:is(.dark .dark\:text-green-400){--tw-text-opacity: 1;color:rgb(74 222 128 / var(--tw-text-opacity))}:is(.dark .dark\:text-primary-300){--tw-text-opacity: 1;color:rgb(165 180 252 / var(--tw-text-opacity))}:is(.dark .dark\:text-red-400){--tw-text-opacity: 1;color:rgb(248 113 113 / var(--tw-text-opacity))}:is(.dark .dark\:text-white){--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity))}:is(.dark .dark\:text-yellow-500){--tw-text-opacity: 1;color:rgb(234 179 8 / var(--tw-text-opacity))}:is(.dark .dark\:hover\:border-gray-600:hover){--tw-border-opacity: 1;border-color:rgb(71 85 105 / var(--tw-border-opacity))}:is(.dark .dark\:hover\:border-gray-700:hover){--tw-border-opacity: 1;border-color:rgb(51 65 85 / var(--tw-border-opacity))}:is(.dark .dark\:hover\:bg-gray-700:hover){--tw-bg-opacity: 1;background-color:rgb(51 65 85 / var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-gray-800:hover){--tw-bg-opacity: 1;background-color:rgb(30 41 59 / var(--tw-bg-opacity))}:is(.dark .dark\:hover\:text-gray-100:hover){--tw-text-opacity: 1;color:rgb(241 245 249 / var(--tw-text-opacity))}:is(.dark .dark\:hover\:text-gray-200:hover){--tw-text-opacity: 1;color:rgb(226 232 240 / var(--tw-text-opacity))}:is(.dark .dark\:hover\:text-gray-300:hover){--tw-text-opacity: 1;color:rgb(203 213 225 / var(--tw-text-opacity))}:is(.dark .dark\:focus\:border-gray-600:focus){--tw-border-opacity: 1;border-color:rgb(71 85 105 / var(--tw-border-opacity))}:is(.dark .dark\:focus\:border-gray-700:focus){--tw-border-opacity: 1;border-color:rgb(51 65 85 / var(--tw-border-opacity))}:is(.dark .dark\:focus\:border-primary-300:focus){--tw-border-opacity: 1;border-color:rgb(165 180 252 / var(--tw-border-opacity))}:is(.dark .dark\:focus\:border-primary-600:focus){--tw-border-opacity: 1;border-color:rgb(79 70 229 / var(--tw-border-opacity))}:is(.dark .dark\:focus\:border-primary-700:focus){--tw-border-opacity: 1;border-color:rgb(67 56 202 / var(--tw-border-opacity))}:is(.dark .dark\:focus\:bg-gray-700:focus){--tw-bg-opacity: 1;background-color:rgb(51 65 85 / var(--tw-bg-opacity))}:is(.dark .dark\:focus\:bg-primary-900:focus){--tw-bg-opacity: 1;background-color:rgb(49 46 129 / var(--tw-bg-opacity))}:is(.dark .dark\:focus\:text-gray-200:focus){--tw-text-opacity: 1;color:rgb(226 232 240 / var(--tw-text-opacity))}:is(.dark .dark\:focus\:text-gray-300:focus){--tw-text-opacity: 1;color:rgb(203 213 225 / var(--tw-text-opacity))}:is(.dark .dark\:focus\:text-primary-200:focus){--tw-text-opacity: 1;color:rgb(199 210 254 / var(--tw-text-opacity))}:is(.dark .dark\:focus\:ring-indigo-600:focus){--tw-ring-opacity: 1;--tw-ring-color: rgb(79 70 229 / var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-primary-600:focus){--tw-ring-opacity: 1;--tw-ring-color: rgb(79 70 229 / var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-primary-700:focus){--tw-ring-opacity: 1;--tw-ring-color: rgb(67 56 202 / var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-opacity-40:focus){--tw-ring-opacity: .4}:is(.dark .dark\:focus\:ring-offset-gray-800:focus){--tw-ring-offset-color: #1e293b}@media (min-width: 640px){.sm\:mx-auto{margin-left:auto;margin-right:auto}.sm\:flex{display:flex}.sm\:hidden{display:none}.sm\:w-full{width:100%}.sm\:max-w-2xl{max-width:42rem}.sm\:max-w-3xl{max-width:48rem}.sm\:max-w-4xl{max-width:56rem}.sm\:max-w-lg{max-width:32rem}.sm\:max-w-md{max-width:28rem}.sm\:max-w-sm{max-width:24rem}.sm\:max-w-xl{max-width:36rem}.sm\:flex-1{flex:1 1 0%}.sm\:translate-y-0{--tw-translate-y: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.sm\:scale-100{--tw-scale-x: 1;--tw-scale-y: 1;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.sm\:scale-95{--tw-scale-x: .95;--tw-scale-y: .95;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.sm\:items-center{align-items:center}.sm\:justify-center{justify-content:center}.sm\:justify-between{justify-content:space-between}.sm\:rounded-md{border-radius:.375rem}.sm\:rounded-bl-md{border-bottom-left-radius:.375rem}.sm\:rounded-br-md{border-bottom-right-radius:.375rem}.sm\:rounded-tl-md{border-top-left-radius:.375rem}.sm\:rounded-tr-md{border-top-right-radius:.375rem}.sm\:p-6{padding:1.5rem}.sm\:px-0{padding-left:0;padding-right:0}.sm\:px-6{padding-left:1.5rem;padding-right:1.5rem}.sm\:pt-0{padding-top:0}.sm\:text-sm{font-size:.875rem;line-height:1.25rem}}@media (min-width: 768px){.md\:col-span-1{grid-column:span 1 / span 1}.md\:block{display:block}.md\:justify-start{justify-content:flex-start}.md\:text-left{text-align:left}}@media (min-width: 1024px){.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.lg\:px-8{padding-left:2rem;padding-right:2rem}} diff --git a/public/build/assets/app-f482c864.css b/public/build/assets/app-f482c864.css deleted file mode 100644 index bcf03a55..00000000 --- a/public/build/assets/app-f482c864.css +++ /dev/null @@ -1 +0,0 @@ -.toast-title{font-weight:700}.toast-message{-ms-word-wrap:break-word;word-wrap:break-word}.toast-message a,.toast-message label{color:#fff}.toast-message a:hover{color:#ccc;text-decoration:none}.toast-close-button{position:relative;right:-.3em;top:-.3em;float:right;font-size:20px;font-weight:700;color:#fff;-webkit-text-shadow:0 1px 0 #ffffff;text-shadow:0 1px 0 #ffffff;opacity:.8;-ms-filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=80);filter:alpha(opacity=80);line-height:1}.toast-close-button:hover,.toast-close-button:focus{color:#000;text-decoration:none;cursor:pointer;opacity:.4;-ms-filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=40);filter:alpha(opacity=40)}.rtl .toast-close-button{left:-.3em;float:left;right:.3em}button.toast-close-button{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.toast-top-center{top:0;right:0;width:100%}.toast-bottom-center{bottom:0;right:0;width:100%}.toast-top-full-width{top:0;right:0;width:100%}.toast-bottom-full-width{bottom:0;right:0;width:100%}.toast-top-left{top:12px;left:12px}.toast-top-right{top:12px;right:12px}.toast-bottom-right{right:12px;bottom:12px}.toast-bottom-left{bottom:12px;left:12px}#toast-container{position:fixed;z-index:999999;pointer-events:none}#toast-container *{box-sizing:border-box}#toast-container>div{border-radius:.5rem;position:relative;pointer-events:auto;overflow:hidden;margin:0 0 6px;padding:15px 15px 15px 50px;width:300px;background-position:15px center;background-repeat:no-repeat;color:#fff}#toast-container>div.rtl{direction:rtl;padding:15px 50px 15px 15px;background-position:right 15px center}#toast-container>div:hover{cursor:pointer;--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}#toast-container>.toast-info{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGwSURBVEhLtZa9SgNBEMc9sUxxRcoUKSzSWIhXpFMhhYWFhaBg4yPYiWCXZxBLERsLRS3EQkEfwCKdjWJAwSKCgoKCcudv4O5YLrt7EzgXhiU3/4+b2ckmwVjJSpKkQ6wAi4gwhT+z3wRBcEz0yjSseUTrcRyfsHsXmD0AmbHOC9Ii8VImnuXBPglHpQ5wwSVM7sNnTG7Za4JwDdCjxyAiH3nyA2mtaTJufiDZ5dCaqlItILh1NHatfN5skvjx9Z38m69CgzuXmZgVrPIGE763Jx9qKsRozWYw6xOHdER+nn2KkO+Bb+UV5CBN6WC6QtBgbRVozrahAbmm6HtUsgtPC19tFdxXZYBOfkbmFJ1VaHA1VAHjd0pp70oTZzvR+EVrx2Ygfdsq6eu55BHYR8hlcki+n+kERUFG8BrA0BwjeAv2M8WLQBtcy+SD6fNsmnB3AlBLrgTtVW1c2QN4bVWLATaIS60J2Du5y1TiJgjSBvFVZgTmwCU+dAZFoPxGEEs8nyHC9Bwe2GvEJv2WXZb0vjdyFT4Cxk3e/kIqlOGoVLwwPevpYHT+00T+hWwXDf4AJAOUqWcDhbwAAAAASUVORK5CYII=)!important}#toast-container>.toast-error{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHOSURBVEhLrZa/SgNBEMZzh0WKCClSCKaIYOED+AAKeQQLG8HWztLCImBrYadgIdY+gIKNYkBFSwu7CAoqCgkkoGBI/E28PdbLZmeDLgzZzcx83/zZ2SSXC1j9fr+I1Hq93g2yxH4iwM1vkoBWAdxCmpzTxfkN2RcyZNaHFIkSo10+8kgxkXIURV5HGxTmFuc75B2RfQkpxHG8aAgaAFa0tAHqYFfQ7Iwe2yhODk8+J4C7yAoRTWI3w/4klGRgR4lO7Rpn9+gvMyWp+uxFh8+H+ARlgN1nJuJuQAYvNkEnwGFck18Er4q3egEc/oO+mhLdKgRyhdNFiacC0rlOCbhNVz4H9FnAYgDBvU3QIioZlJFLJtsoHYRDfiZoUyIxqCtRpVlANq0EU4dApjrtgezPFad5S19Wgjkc0hNVnuF4HjVA6C7QrSIbylB+oZe3aHgBsqlNqKYH48jXyJKMuAbiyVJ8KzaB3eRc0pg9VwQ4niFryI68qiOi3AbjwdsfnAtk0bCjTLJKr6mrD9g8iq/S/B81hguOMlQTnVyG40wAcjnmgsCNESDrjme7wfftP4P7SP4N3CJZdvzoNyGq2c/HWOXJGsvVg+RA/k2MC/wN6I2YA2Pt8GkAAAAASUVORK5CYII=)!important}#toast-container>.toast-success{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADsSURBVEhLY2AYBfQMgf///3P8+/evAIgvA/FsIF+BavYDDWMBGroaSMMBiE8VC7AZDrIFaMFnii3AZTjUgsUUWUDA8OdAH6iQbQEhw4HyGsPEcKBXBIC4ARhex4G4BsjmweU1soIFaGg/WtoFZRIZdEvIMhxkCCjXIVsATV6gFGACs4Rsw0EGgIIH3QJYJgHSARQZDrWAB+jawzgs+Q2UO49D7jnRSRGoEFRILcdmEMWGI0cm0JJ2QpYA1RDvcmzJEWhABhD/pqrL0S0CWuABKgnRki9lLseS7g2AlqwHWQSKH4oKLrILpRGhEQCw2LiRUIa4lwAAAABJRU5ErkJggg==)!important}#toast-container>.toast-warning{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGYSURBVEhL5ZSvTsNQFMbXZGICMYGYmJhAQIJAICYQPAACiSDB8AiICQQJT4CqQEwgJvYASAQCiZiYmJhAIBATCARJy+9rTsldd8sKu1M0+dLb057v6/lbq/2rK0mS/TRNj9cWNAKPYIJII7gIxCcQ51cvqID+GIEX8ASG4B1bK5gIZFeQfoJdEXOfgX4QAQg7kH2A65yQ87lyxb27sggkAzAuFhbbg1K2kgCkB1bVwyIR9m2L7PRPIhDUIXgGtyKw575yz3lTNs6X4JXnjV+LKM/m3MydnTbtOKIjtz6VhCBq4vSm3ncdrD2lk0VgUXSVKjVDJXJzijW1RQdsU7F77He8u68koNZTz8Oz5yGa6J3H3lZ0xYgXBK2QymlWWA+RWnYhskLBv2vmE+hBMCtbA7KX5drWyRT/2JsqZ2IvfB9Y4bWDNMFbJRFmC9E74SoS0CqulwjkC0+5bpcV1CZ8NMej4pjy0U+doDQsGyo1hzVJttIjhQ7GnBtRFN1UarUlH8F3xict+HY07rEzoUGPlWcjRFRr4/gChZgc3ZL2d8oAAAAASUVORK5CYII=)!important}#toast-container.toast-top-center>div,#toast-container.toast-bottom-center>div{width:300px;margin-left:auto;margin-right:auto}#toast-container.toast-top-full-width>div,#toast-container.toast-bottom-full-width>div{width:96%;margin-left:auto;margin-right:auto}.toast{background-color:#030303}.toast-success{--tw-bg-opacity: 1;background-color:rgb(34 197 94 / var(--tw-bg-opacity))}.toast-error{--tw-bg-opacity: 1;background-color:rgb(239 68 68 / var(--tw-bg-opacity))}.toast-info{--tw-bg-opacity: 1;background-color:rgb(99 102 241 / var(--tw-bg-opacity))}.toast-warning{--tw-bg-opacity: 1;background-color:rgb(234 179 8 / var(--tw-bg-opacity))}.toast-progress{position:absolute;left:0;bottom:0;height:4px;background-color:#000;opacity:.4;-ms-filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=40);filter:alpha(opacity=40)}@media all and (max-width: 240px){#toast-container>div{padding:8px 8px 8px 50px;width:11em}#toast-container>div.rtl{padding:8px 50px 8px 8px}#toast-container .toast-close-button{right:-.2em;top:-.2em}#toast-container .rtl .toast-close-button{left:-.2em;right:.2em}}@media all and (min-width: 241px) and (max-width: 480px){#toast-container>div{padding:8px 8px 8px 50px;width:18em}#toast-container>div.rtl{padding:8px 50px 8px 8px}#toast-container .toast-close-button{right:-.2em;top:-.2em}#toast-container .rtl .toast-close-button{left:-.2em;right:.2em}}@media all and (min-width: 481px) and (max-width: 768px){#toast-container>div{padding:15px 15px 15px 50px;width:25em}#toast-container>div.rtl{padding:15px 50px 15px 15px}}/*! tailwindcss v3.3.1 | MIT License | https://tailwindcss.com*/*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e2e8f0}:before,:after{--tw-content: ""}html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:Figtree,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,[type=button],[type=reset],[type=submit]{-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#94a3b8}input::placeholder,textarea::placeholder{opacity:1;color:#94a3b8}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}[type=text],[type=email],[type=url],[type=password],[type=number],[type=date],[type=datetime-local],[type=month],[type=search],[type=tel],[type=time],[type=week],[multiple],textarea,select{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border-color:#64748b;border-width:1px;border-radius:0;padding:.5rem .75rem;font-size:1rem;line-height:1.5rem;--tw-shadow: 0 0 #0000}[type=text]:focus,[type=email]:focus,[type=url]:focus,[type=password]:focus,[type=number]:focus,[type=date]:focus,[type=datetime-local]:focus,[type=month]:focus,[type=search]:focus,[type=tel]:focus,[type=time]:focus,[type=week]:focus,[multiple]:focus,textarea:focus,select:focus{outline:2px solid transparent;outline-offset:2px;--tw-ring-inset: var(--tw-empty, );--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: #2563eb;--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);border-color:#2563eb}input::-moz-placeholder,textarea::-moz-placeholder{color:#64748b;opacity:1}input::placeholder,textarea::placeholder{color:#64748b;opacity:1}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-date-and-time-value{min-height:1.5em}::-webkit-datetime-edit,::-webkit-datetime-edit-year-field,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute-field,::-webkit-datetime-edit-second-field,::-webkit-datetime-edit-millisecond-field,::-webkit-datetime-edit-meridiem-field{padding-top:0;padding-bottom:0}select{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%2364748b' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e");background-position:right .5rem center;background-repeat:no-repeat;background-size:1.5em 1.5em;padding-right:2.5rem;-webkit-print-color-adjust:exact;print-color-adjust:exact}[multiple]{background-image:initial;background-position:initial;background-repeat:unset;background-size:initial;padding-right:.75rem;-webkit-print-color-adjust:unset;print-color-adjust:unset}[type=checkbox],[type=radio]{-webkit-appearance:none;-moz-appearance:none;appearance:none;padding:0;-webkit-print-color-adjust:exact;print-color-adjust:exact;display:inline-block;vertical-align:middle;background-origin:border-box;-webkit-user-select:none;-moz-user-select:none;user-select:none;flex-shrink:0;height:1rem;width:1rem;color:#2563eb;background-color:#fff;border-color:#64748b;border-width:1px;--tw-shadow: 0 0 #0000}[type=checkbox]{border-radius:0}[type=radio]{border-radius:100%}[type=checkbox]:focus,[type=radio]:focus{outline:2px solid transparent;outline-offset:2px;--tw-ring-inset: var(--tw-empty, );--tw-ring-offset-width: 2px;--tw-ring-offset-color: #fff;--tw-ring-color: #2563eb;--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}[type=checkbox]:checked,[type=radio]:checked{border-color:transparent;background-color:currentColor;background-size:100% 100%;background-position:center;background-repeat:no-repeat}[type=checkbox]:checked{background-image:url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e")}[type=radio]:checked{background-image:url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3ccircle cx='8' cy='8' r='3'/%3e%3c/svg%3e")}[type=checkbox]:checked:hover,[type=checkbox]:checked:focus,[type=radio]:checked:hover,[type=radio]:checked:focus{border-color:transparent;background-color:currentColor}[type=checkbox]:indeterminate{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 16'%3e%3cpath stroke='white' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8h8'/%3e%3c/svg%3e");border-color:transparent;background-color:currentColor;background-size:100% 100%;background-position:center;background-repeat:no-repeat}[type=checkbox]:indeterminate:hover,[type=checkbox]:indeterminate:focus{border-color:transparent;background-color:currentColor}[type=file]{background:unset;border-color:inherit;border-width:0;border-radius:0;padding:0;font-size:unset;line-height:inherit}[type=file]:focus{outline:1px solid ButtonText;outline:1px auto -webkit-focus-ring-color}*,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.container{width:100%}@media (min-width: 640px){.container{max-width:640px}}@media (min-width: 768px){.container{max-width:768px}}@media (min-width: 1024px){.container{max-width:1024px}}@media (min-width: 1280px){.container{max-width:1280px}}@media (min-width: 1536px){.container{max-width:1536px}}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.inset-0{inset:0px}.inset-y-0{top:0px;bottom:0px}.left-0{left:0px}.right-0{right:0px}.top-0{top:0px}.top-1{top:.25rem}.z-0{z-index:0}.z-10{z-index:10}.z-50{z-index:50}.float-right{float:right}.mx-5{margin-left:1.25rem;margin-right:1.25rem}.mx-auto{margin-left:auto;margin-right:auto}.-ml-px{margin-left:-1px}.-mr-0{margin-right:-0px}.-mr-0\.5{margin-right:-.125rem}.-mr-2{margin-right:-.5rem}.-mt-px{margin-top:-1px}.mb-1{margin-bottom:.25rem}.mb-10{margin-bottom:2.5rem}.mb-2{margin-bottom:.5rem}.mb-4{margin-bottom:1rem}.mb-5{margin-bottom:1.25rem}.mb-6{margin-bottom:1.5rem}.ml-1{margin-left:.25rem}.ml-12{margin-left:3rem}.ml-2{margin-left:.5rem}.ml-3{margin-left:.75rem}.ml-4{margin-left:1rem}.ml-5{margin-left:1.25rem}.ml-6{margin-left:1.5rem}.mr-1{margin-right:.25rem}.mr-2{margin-right:.5rem}.mt-1{margin-top:.25rem}.mt-10{margin-top:2.5rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.mt-5{margin-top:1.25rem}.mt-6{margin-top:1.5rem}.mt-8{margin-top:2rem}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.hidden{display:none}.h-10{height:2.5rem}.h-16{height:4rem}.h-20{height:5rem}.h-3{height:.75rem}.h-4{height:1rem}.h-48{height:12rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-7{height:1.75rem}.h-8{height:2rem}.h-9{height:2.25rem}.h-96{height:24rem}.h-full{height:100%}.max-h-\[350px\]{max-height:350px}.max-h-screen{max-height:100vh}.min-h-screen{min-height:100vh}.w-1{width:.25rem}.w-10{width:2.5rem}.w-4{width:1rem}.w-48{width:12rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-64{width:16rem}.w-7{width:1.75rem}.w-8{width:2rem}.w-9{width:2.25rem}.w-auto{width:auto}.w-full{width:100%}.w-max{width:-moz-max-content;width:max-content}.min-w-full{min-width:100%}.min-w-max{min-width:-moz-max-content;min-width:max-content}.max-w-6xl{max-width:72rem}.max-w-7xl{max-width:80rem}.max-w-full{max-width:100%}.max-w-xl{max-width:36rem}.flex-1{flex:1 1 0%}.flex-none{flex:none}.shrink-0{flex-shrink:0}.flex-grow{flex-grow:1}.origin-top{transform-origin:top}.origin-top-left{transform-origin:top left}.origin-top-right{transform-origin:top right}.translate-y-0{--tw-translate-y: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-y-4{--tw-translate-y: 1rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.scale-100{--tw-scale-x: 1;--tw-scale-y: 1;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.scale-95{--tw-scale-x: .95;--tw-scale-y: .95;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.cursor-default{cursor:default}.cursor-pointer{cursor:pointer}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.grid-cols-6{grid-template-columns:repeat(6,minmax(0,1fr))}.flex-col{flex-direction:column}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.justify-items-center{justify-items:center}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-5{gap:1.25rem}.space-x-8>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(2rem * var(--tw-space-x-reverse));margin-left:calc(2rem * calc(1 - var(--tw-space-x-reverse)))}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem * var(--tw-space-y-reverse))}.space-y-10>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(2.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(2.5rem * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.75rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem * var(--tw-space-y-reverse))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem * var(--tw-space-y-reverse))}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.overflow-y-hidden{overflow-y:hidden}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-line{white-space:pre-line}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-sm{border-radius:.125rem}.rounded-b-md{border-bottom-right-radius:.375rem;border-bottom-left-radius:.375rem}.rounded-l-md{border-top-left-radius:.375rem;border-bottom-left-radius:.375rem}.rounded-r-md{border-top-right-radius:.375rem;border-bottom-right-radius:.375rem}.rounded-t-md{border-top-left-radius:.375rem;border-top-right-radius:.375rem}.rounded-tr-md{border-top-right-radius:.375rem}.border{border-width:1px}.border-2{border-width:2px}.border-b{border-bottom-width:1px}.border-b-2{border-bottom-width:2px}.border-l{border-left-width:1px}.border-l-4{border-left-width:4px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-gray-100{--tw-border-opacity: 1;border-color:rgb(241 245 249 / var(--tw-border-opacity))}.border-gray-200{--tw-border-opacity: 1;border-color:rgb(226 232 240 / var(--tw-border-opacity))}.border-gray-300{--tw-border-opacity: 1;border-color:rgb(203 213 225 / var(--tw-border-opacity))}.border-gray-400{--tw-border-opacity: 1;border-color:rgb(148 163 184 / var(--tw-border-opacity))}.border-gray-800{--tw-border-opacity: 1;border-color:rgb(30 41 59 / var(--tw-border-opacity))}.border-primary-200{--tw-border-opacity: 1;border-color:rgb(199 210 254 / var(--tw-border-opacity))}.border-primary-400{--tw-border-opacity: 1;border-color:rgb(129 140 248 / var(--tw-border-opacity))}.border-primary-600{--tw-border-opacity: 1;border-color:rgb(79 70 229 / var(--tw-border-opacity))}.border-transparent{border-color:transparent}.border-yellow-500{--tw-border-opacity: 1;border-color:rgb(234 179 8 / var(--tw-border-opacity))}.border-t-transparent{border-top-color:transparent}.bg-gray-100{--tw-bg-opacity: 1;background-color:rgb(241 245 249 / var(--tw-bg-opacity))}.bg-gray-200{--tw-bg-opacity: 1;background-color:rgb(226 232 240 / var(--tw-bg-opacity))}.bg-gray-50{--tw-bg-opacity: 1;background-color:rgb(248 250 252 / var(--tw-bg-opacity))}.bg-gray-500{--tw-bg-opacity: 1;background-color:rgb(100 116 139 / var(--tw-bg-opacity))}.bg-gray-800{--tw-bg-opacity: 1;background-color:rgb(30 41 59 / var(--tw-bg-opacity))}.bg-gray-900{--tw-bg-opacity: 1;background-color:rgb(15 23 42 / var(--tw-bg-opacity))}.bg-green-50{--tw-bg-opacity: 1;background-color:rgb(240 253 244 / var(--tw-bg-opacity))}.bg-primary-200{--tw-bg-opacity: 1;background-color:rgb(199 210 254 / var(--tw-bg-opacity))}.bg-primary-50{--tw-bg-opacity: 1;background-color:rgb(238 242 255 / var(--tw-bg-opacity))}.bg-primary-500{--tw-bg-opacity: 1;background-color:rgb(99 102 241 / var(--tw-bg-opacity))}.bg-primary-600{--tw-bg-opacity: 1;background-color:rgb(79 70 229 / var(--tw-bg-opacity))}.bg-red-50{--tw-bg-opacity: 1;background-color:rgb(254 242 242 / var(--tw-bg-opacity))}.bg-red-600{--tw-bg-opacity: 1;background-color:rgb(220 38 38 / var(--tw-bg-opacity))}.bg-white{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity))}.bg-yellow-100{--tw-bg-opacity: 1;background-color:rgb(254 249 195 / var(--tw-bg-opacity))}.bg-yellow-50{--tw-bg-opacity: 1;background-color:rgb(254 252 232 / var(--tw-bg-opacity))}.fill-current{fill:currentColor}.p-1{padding:.25rem}.p-2{padding:.5rem}.p-3{padding:.75rem}.p-5{padding:1.25rem}.p-6{padding:1.5rem}.p-7{padding:1.75rem}.px-1{padding-left:.25rem;padding-right:.25rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.px-8{padding-left:2rem;padding-right:2rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-12{padding-top:3rem;padding-bottom:3rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-5{padding-top:1.25rem;padding-bottom:1.25rem}.py-6{padding-top:1.5rem;padding-bottom:1.5rem}.pb-1{padding-bottom:.25rem}.pb-2{padding-bottom:.5rem}.pl-3{padding-left:.75rem}.pr-10{padding-right:2.5rem}.pr-2{padding-right:.5rem}.pr-3{padding-right:.75rem}.pr-4{padding-right:1rem}.pt-1{padding-top:.25rem}.pt-3{padding-top:.75rem}.pt-4{padding-top:1rem}.pt-6{padding-top:1.5rem}.pt-8{padding-top:2rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.align-middle{vertical-align:middle}.font-sans{font-family:Figtree,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji"}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-extrabold{font-weight:800}.font-medium{font-weight:500}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.lowercase{text-transform:lowercase}.capitalize{text-transform:capitalize}.leading-4{line-height:1rem}.leading-5{line-height:1.25rem}.leading-7{line-height:1.75rem}.tracking-wider{letter-spacing:.05em}.text-black{--tw-text-opacity: 1;color:rgb(0 0 0 / var(--tw-text-opacity))}.text-gray-100{--tw-text-opacity: 1;color:rgb(241 245 249 / var(--tw-text-opacity))}.text-gray-200{--tw-text-opacity: 1;color:rgb(226 232 240 / var(--tw-text-opacity))}.text-gray-300{--tw-text-opacity: 1;color:rgb(203 213 225 / var(--tw-text-opacity))}.text-gray-400{--tw-text-opacity: 1;color:rgb(148 163 184 / var(--tw-text-opacity))}.text-gray-50{--tw-text-opacity: 1;color:rgb(248 250 252 / var(--tw-text-opacity))}.text-gray-500{--tw-text-opacity: 1;color:rgb(100 116 139 / var(--tw-text-opacity))}.text-gray-600{--tw-text-opacity: 1;color:rgb(71 85 105 / var(--tw-text-opacity))}.text-gray-700{--tw-text-opacity: 1;color:rgb(51 65 85 / var(--tw-text-opacity))}.text-gray-800{--tw-text-opacity: 1;color:rgb(30 41 59 / var(--tw-text-opacity))}.text-gray-900{--tw-text-opacity: 1;color:rgb(15 23 42 / var(--tw-text-opacity))}.text-green-500{--tw-text-opacity: 1;color:rgb(34 197 94 / var(--tw-text-opacity))}.text-green-600{--tw-text-opacity: 1;color:rgb(22 163 74 / var(--tw-text-opacity))}.text-indigo-600{--tw-text-opacity: 1;color:rgb(79 70 229 / var(--tw-text-opacity))}.text-primary-500{--tw-text-opacity: 1;color:rgb(99 102 241 / var(--tw-text-opacity))}.text-primary-600{--tw-text-opacity: 1;color:rgb(79 70 229 / var(--tw-text-opacity))}.text-primary-700{--tw-text-opacity: 1;color:rgb(67 56 202 / var(--tw-text-opacity))}.text-red-500{--tw-text-opacity: 1;color:rgb(239 68 68 / var(--tw-text-opacity))}.text-red-600{--tw-text-opacity: 1;color:rgb(220 38 38 / var(--tw-text-opacity))}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity))}.text-yellow-500{--tw-text-opacity: 1;color:rgb(234 179 8 / var(--tw-text-opacity))}.text-yellow-700{--tw-text-opacity: 1;color:rgb(161 98 7 / var(--tw-text-opacity))}.underline{text-decoration-line:underline}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.opacity-0{opacity:0}.opacity-100{opacity:1}.opacity-25{opacity:.25}.opacity-75{opacity:.75}.shadow{--tw-shadow: 0 1px 3px 0 rgb(0 0 0 / .1), 0 1px 2px -1px rgb(0 0 0 / .1);--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-lg{--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-md{--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-none{--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / .05);--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-xl{--tw-shadow: 0 20px 25px -5px rgb(0 0 0 / .1), 0 8px 10px -6px rgb(0 0 0 / .1);--tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.outline-0{outline-width:0px}.ring-1{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-black{--tw-ring-opacity: 1;--tw-ring-color: rgb(0 0 0 / var(--tw-ring-opacity))}.ring-gray-300{--tw-ring-opacity: 1;--tw-ring-color: rgb(203 213 225 / var(--tw-ring-opacity))}.ring-opacity-5{--tw-ring-opacity: .05}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-100{transition-duration:.1s}.duration-150{transition-duration:.15s}.duration-200{transition-duration:.2s}.duration-300{transition-duration:.3s}.duration-75{transition-duration:75ms}.ease-in{transition-timing-function:cubic-bezier(.4,0,1,1)}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}[x-cloak]{display:none!important}.hover\:border-gray-300:hover{--tw-border-opacity: 1;border-color:rgb(203 213 225 / var(--tw-border-opacity))}.hover\:bg-gray-100:hover{--tw-bg-opacity: 1;background-color:rgb(241 245 249 / var(--tw-bg-opacity))}.hover\:bg-gray-50:hover{--tw-bg-opacity: 1;background-color:rgb(248 250 252 / var(--tw-bg-opacity))}.hover\:bg-gray-900:hover{--tw-bg-opacity: 1;background-color:rgb(15 23 42 / var(--tw-bg-opacity))}.hover\:bg-primary-600:hover{--tw-bg-opacity: 1;background-color:rgb(79 70 229 / var(--tw-bg-opacity))}.hover\:bg-primary-700:hover{--tw-bg-opacity: 1;background-color:rgb(67 56 202 / var(--tw-bg-opacity))}.hover\:bg-red-500:hover{--tw-bg-opacity: 1;background-color:rgb(239 68 68 / var(--tw-bg-opacity))}.hover\:text-gray-400:hover{--tw-text-opacity: 1;color:rgb(148 163 184 / var(--tw-text-opacity))}.hover\:text-gray-500:hover{--tw-text-opacity: 1;color:rgb(100 116 139 / var(--tw-text-opacity))}.hover\:text-gray-700:hover{--tw-text-opacity: 1;color:rgb(51 65 85 / var(--tw-text-opacity))}.hover\:text-gray-800:hover{--tw-text-opacity: 1;color:rgb(30 41 59 / var(--tw-text-opacity))}.hover\:text-gray-900:hover{--tw-text-opacity: 1;color:rgb(15 23 42 / var(--tw-text-opacity))}.hover\:text-white:hover{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity))}.hover\:opacity-50:hover{opacity:.5}.focus\:z-10:focus{z-index:10}.focus\:border-blue-300:focus{--tw-border-opacity: 1;border-color:rgb(147 197 253 / var(--tw-border-opacity))}.focus\:border-gray-300:focus{--tw-border-opacity: 1;border-color:rgb(203 213 225 / var(--tw-border-opacity))}.focus\:border-primary-300:focus{--tw-border-opacity: 1;border-color:rgb(165 180 252 / var(--tw-border-opacity))}.focus\:border-primary-500:focus{--tw-border-opacity: 1;border-color:rgb(99 102 241 / var(--tw-border-opacity))}.focus\:border-primary-700:focus{--tw-border-opacity: 1;border-color:rgb(67 56 202 / var(--tw-border-opacity))}.focus\:border-red-700:focus{--tw-border-opacity: 1;border-color:rgb(185 28 28 / var(--tw-border-opacity))}.focus\:bg-gray-100:focus{--tw-bg-opacity: 1;background-color:rgb(241 245 249 / var(--tw-bg-opacity))}.focus\:bg-gray-50:focus{--tw-bg-opacity: 1;background-color:rgb(248 250 252 / var(--tw-bg-opacity))}.focus\:bg-primary-100:focus{--tw-bg-opacity: 1;background-color:rgb(224 231 255 / var(--tw-bg-opacity))}.focus\:text-gray-500:focus{--tw-text-opacity: 1;color:rgb(100 116 139 / var(--tw-text-opacity))}.focus\:text-gray-700:focus{--tw-text-opacity: 1;color:rgb(51 65 85 / var(--tw-text-opacity))}.focus\:text-gray-800:focus{--tw-text-opacity: 1;color:rgb(30 41 59 / var(--tw-text-opacity))}.focus\:text-primary-800:focus{--tw-text-opacity: 1;color:rgb(55 48 163 / var(--tw-text-opacity))}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring:focus{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus\:ring-1:focus{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus\:ring-2:focus{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus\:ring-gray-400:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(148 163 184 / var(--tw-ring-opacity))}.focus\:ring-gray-500:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(100 116 139 / var(--tw-ring-opacity))}.focus\:ring-gray-700:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(51 65 85 / var(--tw-ring-opacity))}.focus\:ring-indigo-500:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(99 102 241 / var(--tw-ring-opacity))}.focus\:ring-primary-200:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(199 210 254 / var(--tw-ring-opacity))}.focus\:ring-primary-500:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(99 102 241 / var(--tw-ring-opacity))}.focus\:ring-red-200:focus{--tw-ring-opacity: 1;--tw-ring-color: rgb(254 202 202 / var(--tw-ring-opacity))}.focus\:ring-opacity-50:focus{--tw-ring-opacity: .5}.focus\:ring-offset-2:focus{--tw-ring-offset-width: 2px}.active\:bg-gray-100:active{--tw-bg-opacity: 1;background-color:rgb(241 245 249 / var(--tw-bg-opacity))}.active\:bg-primary-700:active{--tw-bg-opacity: 1;background-color:rgb(67 56 202 / var(--tw-bg-opacity))}.active\:bg-red-600:active{--tw-bg-opacity: 1;background-color:rgb(220 38 38 / var(--tw-bg-opacity))}.active\:text-gray-500:active{--tw-text-opacity: 1;color:rgb(100 116 139 / var(--tw-text-opacity))}.active\:text-gray-700:active{--tw-text-opacity: 1;color:rgb(51 65 85 / var(--tw-text-opacity))}.disabled\:opacity-25:disabled{opacity:.25}:is(.dark .dark\:border-r-2){border-right-width:2px}:is(.dark .dark\:border-gray-500){--tw-border-opacity: 1;border-color:rgb(100 116 139 / var(--tw-border-opacity))}:is(.dark .dark\:border-gray-600){--tw-border-opacity: 1;border-color:rgb(71 85 105 / var(--tw-border-opacity))}:is(.dark .dark\:border-gray-700){--tw-border-opacity: 1;border-color:rgb(51 65 85 / var(--tw-border-opacity))}:is(.dark .dark\:border-gray-800){--tw-border-opacity: 1;border-color:rgb(30 41 59 / var(--tw-border-opacity))}:is(.dark .dark\:border-gray-900){--tw-border-opacity: 1;border-color:rgb(15 23 42 / var(--tw-border-opacity))}:is(.dark .dark\:border-primary-600){--tw-border-opacity: 1;border-color:rgb(79 70 229 / var(--tw-border-opacity))}:is(.dark .dark\:border-t-transparent){border-top-color:transparent}:is(.dark .dark\:border-opacity-20){--tw-border-opacity: .2}:is(.dark .dark\:bg-gray-500){--tw-bg-opacity: 1;background-color:rgb(100 116 139 / var(--tw-bg-opacity))}:is(.dark .dark\:bg-gray-700){--tw-bg-opacity: 1;background-color:rgb(51 65 85 / var(--tw-bg-opacity))}:is(.dark .dark\:bg-gray-800){--tw-bg-opacity: 1;background-color:rgb(30 41 59 / var(--tw-bg-opacity))}:is(.dark .dark\:bg-gray-800\/50){background-color:#1e293b80}:is(.dark .dark\:bg-gray-900){--tw-bg-opacity: 1;background-color:rgb(15 23 42 / var(--tw-bg-opacity))}:is(.dark .dark\:bg-green-500){--tw-bg-opacity: 1;background-color:rgb(34 197 94 / var(--tw-bg-opacity))}:is(.dark .dark\:bg-primary-500){--tw-bg-opacity: 1;background-color:rgb(99 102 241 / var(--tw-bg-opacity))}:is(.dark .dark\:bg-primary-900\/50){background-color:#312e8180}:is(.dark .dark\:bg-red-500){--tw-bg-opacity: 1;background-color:rgb(239 68 68 / var(--tw-bg-opacity))}:is(.dark .dark\:bg-yellow-500){--tw-bg-opacity: 1;background-color:rgb(234 179 8 / var(--tw-bg-opacity))}:is(.dark .dark\:bg-opacity-10){--tw-bg-opacity: .1}:is(.dark .dark\:bg-opacity-20){--tw-bg-opacity: .2}:is(.dark .dark\:bg-opacity-30){--tw-bg-opacity: .3}:is(.dark .dark\:bg-opacity-70){--tw-bg-opacity: .7}:is(.dark .dark\:text-gray-100){--tw-text-opacity: 1;color:rgb(241 245 249 / var(--tw-text-opacity))}:is(.dark .dark\:text-gray-200){--tw-text-opacity: 1;color:rgb(226 232 240 / var(--tw-text-opacity))}:is(.dark .dark\:text-gray-300){--tw-text-opacity: 1;color:rgb(203 213 225 / var(--tw-text-opacity))}:is(.dark .dark\:text-gray-400){--tw-text-opacity: 1;color:rgb(148 163 184 / var(--tw-text-opacity))}:is(.dark .dark\:text-gray-500){--tw-text-opacity: 1;color:rgb(100 116 139 / var(--tw-text-opacity))}:is(.dark .dark\:text-green-400){--tw-text-opacity: 1;color:rgb(74 222 128 / var(--tw-text-opacity))}:is(.dark .dark\:text-primary-300){--tw-text-opacity: 1;color:rgb(165 180 252 / var(--tw-text-opacity))}:is(.dark .dark\:text-red-400){--tw-text-opacity: 1;color:rgb(248 113 113 / var(--tw-text-opacity))}:is(.dark .dark\:text-white){--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity))}:is(.dark .dark\:text-yellow-500){--tw-text-opacity: 1;color:rgb(234 179 8 / var(--tw-text-opacity))}:is(.dark .dark\:hover\:border-gray-600:hover){--tw-border-opacity: 1;border-color:rgb(71 85 105 / var(--tw-border-opacity))}:is(.dark .dark\:hover\:border-gray-700:hover){--tw-border-opacity: 1;border-color:rgb(51 65 85 / var(--tw-border-opacity))}:is(.dark .dark\:hover\:bg-gray-700:hover){--tw-bg-opacity: 1;background-color:rgb(51 65 85 / var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-gray-800:hover){--tw-bg-opacity: 1;background-color:rgb(30 41 59 / var(--tw-bg-opacity))}:is(.dark .dark\:hover\:bg-gray-900:hover){--tw-bg-opacity: 1;background-color:rgb(15 23 42 / var(--tw-bg-opacity))}:is(.dark .dark\:hover\:text-gray-100:hover){--tw-text-opacity: 1;color:rgb(241 245 249 / var(--tw-text-opacity))}:is(.dark .dark\:hover\:text-gray-200:hover){--tw-text-opacity: 1;color:rgb(226 232 240 / var(--tw-text-opacity))}:is(.dark .dark\:hover\:text-gray-300:hover){--tw-text-opacity: 1;color:rgb(203 213 225 / var(--tw-text-opacity))}:is(.dark .dark\:hover\:text-gray-400:hover){--tw-text-opacity: 1;color:rgb(148 163 184 / var(--tw-text-opacity))}:is(.dark .dark\:focus\:border-gray-600:focus){--tw-border-opacity: 1;border-color:rgb(71 85 105 / var(--tw-border-opacity))}:is(.dark .dark\:focus\:border-gray-700:focus){--tw-border-opacity: 1;border-color:rgb(51 65 85 / var(--tw-border-opacity))}:is(.dark .dark\:focus\:border-primary-300:focus){--tw-border-opacity: 1;border-color:rgb(165 180 252 / var(--tw-border-opacity))}:is(.dark .dark\:focus\:border-primary-600:focus){--tw-border-opacity: 1;border-color:rgb(79 70 229 / var(--tw-border-opacity))}:is(.dark .dark\:focus\:border-primary-700:focus){--tw-border-opacity: 1;border-color:rgb(67 56 202 / var(--tw-border-opacity))}:is(.dark .dark\:focus\:bg-gray-700:focus){--tw-bg-opacity: 1;background-color:rgb(51 65 85 / var(--tw-bg-opacity))}:is(.dark .dark\:focus\:bg-gray-800:focus){--tw-bg-opacity: 1;background-color:rgb(30 41 59 / var(--tw-bg-opacity))}:is(.dark .dark\:focus\:bg-gray-900:focus){--tw-bg-opacity: 1;background-color:rgb(15 23 42 / var(--tw-bg-opacity))}:is(.dark .dark\:focus\:bg-primary-900:focus){--tw-bg-opacity: 1;background-color:rgb(49 46 129 / var(--tw-bg-opacity))}:is(.dark .dark\:focus\:text-gray-200:focus){--tw-text-opacity: 1;color:rgb(226 232 240 / var(--tw-text-opacity))}:is(.dark .dark\:focus\:text-gray-300:focus){--tw-text-opacity: 1;color:rgb(203 213 225 / var(--tw-text-opacity))}:is(.dark .dark\:focus\:text-gray-400:focus){--tw-text-opacity: 1;color:rgb(148 163 184 / var(--tw-text-opacity))}:is(.dark .dark\:focus\:text-primary-200:focus){--tw-text-opacity: 1;color:rgb(199 210 254 / var(--tw-text-opacity))}:is(.dark .dark\:focus\:ring-indigo-600:focus){--tw-ring-opacity: 1;--tw-ring-color: rgb(79 70 229 / var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-primary-600:focus){--tw-ring-opacity: 1;--tw-ring-color: rgb(79 70 229 / var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-primary-700:focus){--tw-ring-opacity: 1;--tw-ring-color: rgb(67 56 202 / var(--tw-ring-opacity))}:is(.dark .dark\:focus\:ring-opacity-40:focus){--tw-ring-opacity: .4}:is(.dark .dark\:focus\:ring-offset-gray-800:focus){--tw-ring-offset-color: #1e293b}@media (min-width: 640px){.sm\:-my-px{margin-top:-1px;margin-bottom:-1px}.sm\:mx-auto{margin-left:auto;margin-right:auto}.sm\:ml-10{margin-left:2.5rem}.sm\:ml-6{margin-left:1.5rem}.sm\:flex{display:flex}.sm\:hidden{display:none}.sm\:w-full{width:100%}.sm\:max-w-2xl{max-width:42rem}.sm\:max-w-3xl{max-width:48rem}.sm\:max-w-4xl{max-width:56rem}.sm\:max-w-lg{max-width:32rem}.sm\:max-w-md{max-width:28rem}.sm\:max-w-sm{max-width:24rem}.sm\:max-w-xl{max-width:36rem}.sm\:flex-1{flex:1 1 0%}.sm\:translate-y-0{--tw-translate-y: 0px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.sm\:scale-100{--tw-scale-x: 1;--tw-scale-y: 1;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.sm\:scale-95{--tw-scale-x: .95;--tw-scale-y: .95;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.sm\:items-center{align-items:center}.sm\:justify-start{justify-content:flex-start}.sm\:justify-center{justify-content:center}.sm\:justify-between{justify-content:space-between}.sm\:rounded-md{border-radius:.375rem}.sm\:rounded-bl-md{border-bottom-left-radius:.375rem}.sm\:rounded-br-md{border-bottom-right-radius:.375rem}.sm\:rounded-tl-md{border-top-left-radius:.375rem}.sm\:rounded-tr-md{border-top-right-radius:.375rem}.sm\:p-6{padding:1.5rem}.sm\:px-0{padding-left:0;padding-right:0}.sm\:px-6{padding-left:1.5rem;padding-right:1.5rem}.sm\:pt-0{padding-top:0}.sm\:text-sm{font-size:.875rem;line-height:1.25rem}}@media (min-width: 768px){.md\:col-span-1{grid-column:span 1 / span 1}.md\:block{display:block}.md\:justify-start{justify-content:flex-start}.md\:text-left{text-align:left}}@media (min-width: 1024px){.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.lg\:px-5{padding-left:1.25rem;padding-right:1.25rem}.lg\:px-8{padding-left:2rem;padding-right:2rem}} diff --git a/public/build/manifest.json b/public/build/manifest.json index a9aa8f6a..7accad1c 100644 --- a/public/build/manifest.json +++ b/public/build/manifest.json @@ -1,6 +1,6 @@ { "resources/css/app.css": { - "file": "assets/app-f482c864.css", + "file": "assets/app-8b808e33.css", "isEntry": true, "src": "resources/css/app.css" }, diff --git a/resources/views/components/dropdown-link.blade.php b/resources/views/components/dropdown-link.blade.php index b1d68b81..0fbeb796 100644 --- a/resources/views/components/dropdown-link.blade.php +++ b/resources/views/components/dropdown-link.blade.php @@ -1 +1 @@ -merge(['class' => 'block w-full px-4 py-2 text-left text-sm leading-5 text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800 focus:outline-none focus:bg-gray-100 dark:focus:bg-gray-800 transition duration-150 ease-in-out flex items-center justify-start']) }}>{{ $slot }} +merge(['class' => 'block w-full px-4 py-2 text-left text-sm leading-5 text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 focus:outline-none focus:bg-gray-100 dark:focus:bg-gray-700 transition duration-150 ease-in-out flex items-center justify-start']) }}>{{ $slot }} diff --git a/resources/views/components/dropdown.blade.php b/resources/views/components/dropdown.blade.php index 94283f01..443cec70 100644 --- a/resources/views/components/dropdown.blade.php +++ b/resources/views/components/dropdown.blade.php @@ -1,4 +1,4 @@ -@props(['align' => 'right', 'width' => '48', 'contentClasses' => 'py-1 bg-white dark:bg-gray-700']) +@props(['align' => 'right', 'width' => '48', 'contentClasses' => 'py-1 bg-white dark:bg-gray-800']) @php switch ($align) { diff --git a/resources/views/layouts/app.blade.php b/resources/views/layouts/app.blade.php index 438103af..e5823945 100644 --- a/resources/views/layouts/app.blade.php +++ b/resources/views/layouts/app.blade.php @@ -1,5 +1,5 @@ @props(['server']) - + @@ -32,7 +32,7 @@ + x-data="" x-cloak>
@@ -58,9 +58,9 @@ class="left-0 top-0 min-h-screen w-64 flex-none bg-gray-800 dark:bg-gray-800/50
+ stroke="currentColor" class="w-6 h-6"> + d="M2.25 12l8.954-8.955c.44-.439 1.152-.439 1.591 0L21.75 12M4.5 9.75v10.125c0 .621.504 1.125 1.125 1.125H9.75v-4.875c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125V21h4.125c.621 0 1.125-.504 1.125-1.125V9.75M8.25 21h8.25" /> {{ __('Overview') }} @@ -68,9 +68,9 @@ class="left-0 top-0 min-h-screen w-64 flex-none bg-gray-800 dark:bg-gray-800/50 @if ($server->webserver()) + stroke-width="1.5" stroke="currentColor" class="w-6 h-6"> + d="M12 21a9.004 9.004 0 008.716-6.747M12 21a9.004 9.004 0 01-8.716-6.747M12 21c2.485 0 4.5-4.03 4.5-9S14.485 3 12 3m0 18c-2.485 0-4.5-4.03-4.5-9S9.515 3 12 3m0 0a8.997 8.997 0 017.843 4.582M12 3a8.997 8.997 0 00-7.843 4.582m15.686 0A11.953 11.953 0 0112 10.5c-2.998 0-5.74-1.1-7.843-2.918m15.686 0A8.959 8.959 0 0121 12c0 .778-.099 1.533-.284 2.253m0 0A17.919 17.919 0 0112 16.5c-3.162 0-6.133-.815-8.716-2.247m0 0A9.015 9.015 0 013 12c0-1.605.42-3.113 1.157-4.418" /> {{ __('Sites') }} @@ -79,9 +79,9 @@ class="left-0 top-0 min-h-screen w-64 flex-none bg-gray-800 dark:bg-gray-800/50 + stroke-width="1.5" stroke="currentColor" class="w-6 h-6"> + d="M20.25 6.375c0 2.278-3.694 4.125-8.25 4.125S3.75 8.653 3.75 6.375m16.5 0c0-2.278-3.694-4.125-8.25-4.125S3.75 4.097 3.75 6.375m16.5 0v11.25c0 2.278-3.694 4.125-8.25 4.125s-8.25-1.847-8.25-4.125V6.375m16.5 0v3.75m-16.5-3.75v3.75m16.5 0v3.75C20.25 16.153 16.556 18 12 18s-8.25-1.847-8.25-4.125v-3.75m16.5 0c0 2.278-3.694 4.125-8.25 4.125s-8.25-1.847-8.25-4.125" /> {{ __('Databases') }} @@ -89,9 +89,9 @@ class="left-0 top-0 min-h-screen w-64 flex-none bg-gray-800 dark:bg-gray-800/50 @if ($server->php()) + stroke-width="1.5" stroke="currentColor" class="w-6 h-6"> + d="M17.25 6.75L22.5 12l-5.25 5.25m-10.5 0L1.5 12l5.25-5.25m7.5-3l-4.5 16.5" /> {{ __('PHP') }} @@ -99,55 +99,53 @@ class="left-0 top-0 min-h-screen w-64 flex-none bg-gray-800 dark:bg-gray-800/50 @if ($server->firewall()) + stroke-width="1.5" stroke="currentColor" class="w-6 h-6"> + d="M15.362 5.214A8.252 8.252 0 0112 21 8.25 8.25 0 016.038 7.048 8.287 8.287 0 009 9.6a8.983 8.983 0 013.361-6.867 8.21 8.21 0 003 2.48z" /> + d="M12 18a3.75 3.75 0 00.495-7.467 5.99 5.99 0 00-1.925 3.546 5.974 5.974 0 01-2.133-1A3.75 3.75 0 0012 18z" /> {{ __('Firewall') }} @endif + stroke-width="1.5" stroke="currentColor" class="w-6 h-6"> - + d="M12 6v6h4.5m4.5 0a9 9 0 11-18 0 9 9 0 0118 0z" /> {{ __('Cronjobs') }} + stroke-width="1.5" stroke="currentColor" class="w-6 h-6"> + d="M15.75 5.25a3 3 0 013 3m3 0a6 6 0 01-7.029 5.912c-.563-.097-1.159.026-1.563.43L10.5 17.25H8.25v2.25H6v2.25H2.25v-2.818c0-.597.237-1.17.659-1.591l6.499-6.499c.404-.404.527-1 .43-1.563A6 6 0 1121.75 8.25z" /> {{ __('SSH Keys') }} + stroke-width="1.5" stroke="currentColor" class="w-6 h-6"> + d="M9.594 3.94c.09-.542.56-.94 1.11-.94h2.593c.55 0 1.02.398 1.11.94l.213 1.281c.063.374.313.686.645.87.074.04.147.083.22.127.324.196.72.257 1.075.124l1.217-.456a1.125 1.125 0 011.37.49l1.296 2.247a1.125 1.125 0 01-.26 1.431l-1.003.827c-.293.24-.438.613-.431.992a6.759 6.759 0 010 .255c-.007.378.138.75.43.99l1.005.828c.424.35.534.954.26 1.43l-1.298 2.247a1.125 1.125 0 01-1.369.491l-1.217-.456c-.355-.133-.75-.072-1.076.124a6.57 6.57 0 01-.22.128c-.331.183-.581.495-.644.869l-.213 1.28c-.09.543-.56.941-1.11.941h-2.594c-.55 0-1.02-.398-1.11-.94l-.213-1.281c-.062-.374-.312-.686-.644-.87a6.52 6.52 0 01-.22-.127c-.325-.196-.72-.257-1.076-.124l-1.217.456a1.125 1.125 0 01-1.369-.49l-1.297-2.247a1.125 1.125 0 01.26-1.431l1.004-.827c.292-.24.437-.613.43-.992a6.932 6.932 0 010-.255c.007-.378-.138-.75-.43-.99l-1.004-.828a1.125 1.125 0 01-.26-1.43l1.297-2.247a1.125 1.125 0 011.37-.491l1.216.456c.356.133.751.072 1.076-.124.072-.044.146-.087.22-.128.332-.183.582-.495.644-.869l.214-1.281z" /> - + d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" /> {{ __('Services') }} @endif + stroke-width="1.5" stroke="currentColor" class="w-6 h-6"> + d="M11.42 15.17L17.25 21A2.652 2.652 0 0021 17.25l-5.877-5.877M11.42 15.17l2.496-3.03c.317-.384.74-.626 1.208-.766M11.42 15.17l-4.655 5.653a2.548 2.548 0 11-3.586-3.586l6.837-5.63m5.108-.233c.55-.164 1.163-.188 1.743-.14a4.5 4.5 0 004.486-6.336l-3.276 3.277a3.004 3.004 0 01-2.25-2.25l3.276-3.276a4.5 4.5 0 00-6.336 4.486c.091 1.076-.071 2.264-.904 2.95l-.102.085m-1.745 1.437L5.909 7.5H4.5L2.25 3.75l1.5-1.5L7.5 4.5v1.409l4.26 4.26m-1.745 1.437l1.745-1.437m6.615 8.206L15.75 15.75M4.867 19.125h.008v.008h-.008v-.008z" /> {{ __('Settings') }} + stroke-width="1.5" stroke="currentColor" class="w-6 h-6"> + d="M6.429 9.75L2.25 12l4.179 2.25m0-4.5l5.571 3 5.571-3m-11.142 0L2.25 7.5 12 2.25l9.75 5.25-4.179 2.25m0 0L21.75 12l-4.179 2.25m0 0l4.179 2.25L12 21.75 2.25 16.5l4.179-2.25m11.142 0l-5.571 3-5.571-3" /> {{ __('Logs') }} @@ -164,48 +162,7 @@ class="min-h-screen w-64 flex-none border-r border-gray-200 bg-white dark:border @endif
- + @include('layouts.navigation') @if (isset($header)) @@ -244,7 +201,7 @@ class="min-h-screen w-64 flex-none border-r border-gray-200 bg-white dark:border // On page load or when changing themes, best to add inline in `head` to avoid FOUC if (localStorage.theme === 'dark' || (!('theme' in localStorage) && window.matchMedia( - '(prefers-color-scheme: dark)').matches)) { + '(prefers-color-scheme: dark)').matches)) { document.documentElement.classList.add('dark') } else { document.documentElement.classList.remove('dark') diff --git a/resources/views/layouts/navigation.blade.php b/resources/views/layouts/navigation.blade.php index 359d3716..fda604fa 100644 --- a/resources/views/layouts/navigation.blade.php +++ b/resources/views/layouts/navigation.blade.php @@ -1,61 +1,16 @@ -