From 9aa1b3ab8ec6ab7bf658e4e58e732e6b86314eb1 Mon Sep 17 00:00:00 2001 From: Gitea Date: Fri, 25 Apr 2025 17:43:35 +0530 Subject: [PATCH] Added Create Custom, Random, Gmail Generation --- app/Http/Controllers/AppController.php | 54 ++++ app/Livewire/Email.php | 13 + app/Livewire/EmailInbox.php | 62 +++++ app/Livewire/Frontend/Action.php | 134 ++++++++++ app/Livewire/Frontend/ActionOld.php | 222 ++++++++++++++++ app/Livewire/Frontend/App.php | 109 ++++++++ app/Livewire/Frontend/Email.php | 65 +++++ app/Livewire/Home.php | 13 + app/Livewire/Inbox.php | 13 + app/Models/Message.php | 242 +++++++++++++++++- app/Models/ZEmail.php | 108 +------- composer.json | 1 + composer.lock | 65 ++++- public/images/logo.webp | Bin 0 -> 4694 bytes public/images/user.webp | Bin 0 -> 13056 bytes public/images/zemail-logo-dark.webp | Bin 0 -> 17258 bytes public/images/zemail-logo-light.webp | Bin 0 -> 16662 bytes resources/css/app.css | 45 +++- resources/css/boil.css | 61 ++++- resources/js/boil.js | 69 +++++ .../views/components/layouts/app.blade.php | 129 ++++++++++ .../views/filament/pages/setting.blade.php | 3 - .../flux/icon/circle-user-round.blade.php | 43 ++++ resources/views/flux/icon/download.blade.php | 43 ++++ resources/views/flux/icon/file-down.blade.php | 44 ++++ resources/views/flux/icon/file.blade.php | 42 +++ resources/views/flux/icon/mail-plus.blade.php | 44 ++++ resources/views/flux/icon/mail.blade.php | 42 +++ .../views/flux/icon/refresh-cw.blade.php | 44 ++++ resources/views/flux/icon/sparkle.blade.php | 41 +++ .../views/livewire/email-inbox.blade.php | 51 ++++ resources/views/livewire/email.blade.php | 54 ++++ .../views/livewire/frontend/action.blade.php | 42 +++ .../views/livewire/frontend/app.blade.php | 3 + .../views/livewire/frontend/email.blade.php | 13 + resources/views/livewire/home.blade.php | 11 + resources/views/livewire/inbox.blade.php | 48 ++++ routes/web.php | 28 +- vite.config.js | 2 +- 39 files changed, 1867 insertions(+), 136 deletions(-) create mode 100644 app/Http/Controllers/AppController.php create mode 100644 app/Livewire/Email.php create mode 100644 app/Livewire/EmailInbox.php create mode 100644 app/Livewire/Frontend/Action.php create mode 100644 app/Livewire/Frontend/ActionOld.php create mode 100644 app/Livewire/Frontend/App.php create mode 100644 app/Livewire/Frontend/Email.php create mode 100644 app/Livewire/Home.php create mode 100644 app/Livewire/Inbox.php create mode 100644 public/images/logo.webp create mode 100644 public/images/user.webp create mode 100644 public/images/zemail-logo-dark.webp create mode 100644 public/images/zemail-logo-light.webp create mode 100644 resources/js/boil.js create mode 100644 resources/views/components/layouts/app.blade.php delete mode 100644 resources/views/filament/pages/setting.blade.php create mode 100644 resources/views/flux/icon/circle-user-round.blade.php create mode 100644 resources/views/flux/icon/download.blade.php create mode 100644 resources/views/flux/icon/file-down.blade.php create mode 100644 resources/views/flux/icon/file.blade.php create mode 100644 resources/views/flux/icon/mail-plus.blade.php create mode 100644 resources/views/flux/icon/mail.blade.php create mode 100644 resources/views/flux/icon/refresh-cw.blade.php create mode 100644 resources/views/flux/icon/sparkle.blade.php create mode 100644 resources/views/livewire/email-inbox.blade.php create mode 100644 resources/views/livewire/email.blade.php create mode 100644 resources/views/livewire/frontend/action.blade.php create mode 100644 resources/views/livewire/frontend/app.blade.php create mode 100644 resources/views/livewire/frontend/email.blade.php create mode 100644 resources/views/livewire/home.blade.php create mode 100644 resources/views/livewire/inbox.blade.php diff --git a/app/Http/Controllers/AppController.php b/app/Http/Controllers/AppController.php new file mode 100644 index 0000000..c1e8bfe --- /dev/null +++ b/app/Http/Controllers/AppController.php @@ -0,0 +1,54 @@ +enable_create_from_url) { + ZEmail::createCustomEmailFull($email); + } + return redirect()->route('mailbox'); + } + if (!ZEmail::getEmail()) { + return redirect()->route('home'); + } + if (json_decode(config('app.settings.configuration_settings'))->disable_mailbox_slug) { + return redirect()->route('home'); + } + return $this->app(); + } + + public function app() { + return redirect()->route('home'); + } + + private function getStringBetween($string, $start, $end) { + $string = ' ' . $string; + $ini = strpos($string, $start); + if ($ini == 0) return ''; + $ini += strlen($start); + $len = strpos($string, $end, $ini) - $ini; + return substr($string, $ini, $len); + } + private function setHeaders($page) { + $header = $page->header; + foreach ($page->meta ? unserialize($page->meta) : [] as $meta) { + if ($meta['name'] == 'canonical') { + $header .= ''; + } else if (str_contains($meta['name'], 'og:')) { + $header .= ''; + } else { + $header .= ''; + } + } + $page->header = $header; + return $page; + } + + +} diff --git a/app/Livewire/Email.php b/app/Livewire/Email.php new file mode 100644 index 0000000..6b4f259 --- /dev/null +++ b/app/Livewire/Email.php @@ -0,0 +1,13 @@ +currentEmail = ZEmail::getEmail(); + $this->loadMessages(); + } + + public function loadMessages() + { + if ($this->currentEmail) { + $this->messages = ZEmail::getMessages($this->currentEmail); + } + } + + public function selectMessage($messageId) + { + $this->selectedMessage = $messageId; + } + + public function deleteMessage($messageId) + { + ZEmail::deleteMessage($messageId); + $this->loadMessages(); + $this->selectedMessage = null; + } + + public function generateNewEmail() + { + $this->currentEmail = ZEmail::generateRandomEmail(); + $this->loadMessages(); + } + + public function getPollingInterval() + { + return $this->refreshInterval * 1000; // Convert to milliseconds + } + + public function render() + { + return view('livewire.email-inbox', [ + 'messages' => $this->messages, + 'currentEmail' => $this->currentEmail + ]); + } +} diff --git a/app/Livewire/Frontend/Action.php b/app/Livewire/Frontend/Action.php new file mode 100644 index 0000000..626f823 --- /dev/null +++ b/app/Livewire/Frontend/Action.php @@ -0,0 +1,134 @@ +domains = json_decode(config('app.settings.configuration_settings'))->domains ?? []; + $this->email = ZEmail::getEmail(); + $this->emails = ZEmail::getEmails(); + $this->validateDomainInEmail(); + } + + public function create() { + if (!$this->username) { + return $this->showAlert('error', __('Please enter Username')); + } + $this->checkDomainInUsername(); + if (strlen($this->username) < json_decode(config('app.settings.configuration_settings'))->custom_username_length_min || strlen($this->username) > json_decode(config('app.settings.configuration_settings'))->custom_username_length_max) { + return $this->showAlert('error', __('Username length cannot be less than') . ' ' . json_decode(config('app.settings.configuration_settings'))->custom_username_length_min . ' ' . __('and greater than') . ' ' . json_decode(config('app.settings.configuration_settings'))->custom_username_length_max); + } + if (!$this->domain) { + return $this->showAlert('error', __('Please Select a Domain')); + } + if (in_array($this->username, json_decode(config('app.settings.configuration_settings'))->forbidden_ids)) { + return $this->showAlert('error', __('Username not allowed')); + } + if (!$this->checkEmailLimit()) { + return $this->showAlert('error', __('You have reached daily limit of MAX ') . json_decode(config('app.settings.configuration_settings'))->email_limit . __(' temp mail')); + } + if (!$this->checkUsedEmail()) { + return $this->showAlert('error', __('Sorry! That email is already been used by someone else. Please try a different email address.')); + } + + $this->email = ZEmail::createCustomEmail($this->username, $this->domain); + $this->dispatch('updateEmail'); + $this->dispatch('closeModal'); + + } + public function random() { + if (!$this->checkEmailLimit()) { + return $this->showAlert('error', __('You have reached daily limit of maximum ') . json_decode(config('app.settings.configuration_settings'))->email_limit . __(' temp mail addresses.')); + } + $this->email = ZEmail::generateRandomEmail(); + $this->dispatch('updateEmail'); + $this->dispatch('closeModal'); + + //$this->redirect(route('mailbox')); + } + + public function gmail() { + if (!$this->checkEmailLimit()) { + return $this->showAlert('error', __('You have reached daily limit of maximum ') . json_decode(config('app.settings.configuration_settings'))->email_limit . __(' temp mail addresses.')); + } + $this->email = ZEmail::generateRandomGmail(); + $this->dispatch('updateEmail'); + $this->dispatch('closeModal'); + } + + public function deleteEmail() { + ZEmail::removeEmail($this->email); +// if (count($this->emails) <= 1 && json_decode(config('app.settings.configuration_settings'))->after_last_email_delete == 'redirect_to_homepage') { +// return redirect()->route('home'); +// } + $this->email = ZEmail::getEmail(true); + $this->emails = ZEmail::getEmails(); + + $this->dispatch('updateEmail'); + $this->dispatch('closeModal'); + } + + private function showAlert($type, $message): void + { + $this->dispatch('showAlert', ['type' => $type, 'message' => $message]); + } + + private function checkEmailLimit() { + $logs = Log::select('ip', 'email')->where('ip', request()->ip())->where('created_at', '>', Carbon::now()->subDay())->groupBy('email')->groupBy('ip')->get(); + if (count($logs) >= json_decode(config('app.settings.configuration_settings'))->email_limit) { + return false; + } + return true; + } + + private function checkUsedEmail() { + if (json_decode(config('app.settings.configuration_settings'))->disable_used_email) { + $check = Log::where('email', $this->user . '@' . $this->domain)->where('ip', '<>', request()->ip())->count(); + if ($check > 0) { + return false; + } + return true; + } + return true; + } + + private function checkDomainInUsername() { + $parts = explode('@', $this->username); + if (isset($parts[1])) { + if (in_array($parts[1], $this->domains)) { + $this->domain = $parts[1]; + } + $this->username = $parts[0]; + } + } + + private function validateDomainInEmail(): void + { + $data = explode('@', $this->email); + if (isset($data[1])) { + $domain = $data[1]; + $domains = json_decode(config('app.settings.configuration_settings'))->domains ?? []; + if (!in_array($domain, $domains)) { + $key = array_search($this->email, $this->emails); + ZEmail::removeEmail($this->email); + if ($key == 0 && count($this->emails) == 1 && json_decode(config('app.settings.configuration_settings'))->after_last_email_delete == 'redirect_to_homepage') { + redirect()->route('home'); + } else { + redirect()->route('mailbox'); + } + } + } + } + public function render() { + return view('livewire.frontend.action'); + } +} diff --git a/app/Livewire/Frontend/ActionOld.php b/app/Livewire/Frontend/ActionOld.php new file mode 100644 index 0000000..1931052 --- /dev/null +++ b/app/Livewire/Frontend/ActionOld.php @@ -0,0 +1,222 @@ +domains = config('app.settings.domains'); + $this->email = ZEmail::getEmail(); + $this->emails = ZEmail::getEmails(); + $this->validateDomainInEmail(); + } + + public function refreshMessages() + { + $this->emit('fetchMessages'); + } + + public function loadMsg($email) { + $this->email = $email; + if (count($this->emails) == 0) { + $this->emails = [$email]; + } + } + + public function syncEmail($email) { + $this->email = $email; + if (count($this->emails) == 0) { + $this->emails = [$email]; + } + } + + public function setDomain($domain) { + $this->domain = $domain; + } + + public function checkReCaptcha3($token, $action) { + $response = Http::post('https://www.google.com/recaptcha/api/siteverify?secret=' . config('app.settings.recaptcha3.secret_key') . '&response=' . $token); + $data = $response->json(); + if ($data['success']) { + $captcha = $data['score']; + if ($captcha > 0.5) { + if ($action == 'create') { + $this->create(); + } else { + $this->random(); + } + } else { + return $this->showAlert('error', __('Captcha Failed! Please try again')); + } + } else { + return $this->showAlert('error', __('Captcha Failed! Error: ') . json_encode($data['error-codes'])); + } + } + public function create() { + if (!$this->user) { + return $this->showAlert('error', __('Please enter Username')); + } + $this->checkDomainInUsername(); + if (strlen($this->user) < config('app.settings.custom.min') || strlen($this->user) > config('app.settings.custom.max')) { + return $this->showAlert('error', __('Username length cannot be less than') . ' ' . config('app.settings.custom.min') . ' ' . __('and greater than') . ' ' . config('app.settings.custom.max')); + } + if (!$this->domain) { + return $this->showAlert('error', __('Please Select a Domain')); + } + if (in_array($this->user, config('app.settings.forbidden_ids'))) { + return $this->showAlert('error', __('Username not allowed')); + } + if (!$this->checkEmailLimit()) { + return $this->showAlert('error', __('You have reached daily limit of MAX ') . config('app.settings.email_limit', 5) . __(' temp mail')); + } + if (!$this->checkUsedEmail()) { + return $this->showAlert('error', __('Sorry! That email is already been used by someone else. Please try a different email address.')); + } + if (!$this->validateCaptcha()) { + return $this->showAlert('error', __('Invalid Captcha. Please try again')); + } + $this->email = ZEmail::createCustomEmail($this->user, $this->domain); + $this->redirect(route('mailbox')); + } + + public function random() { + if (!$this->checkEmailLimit()) { + return $this->showAlert('error', __('You have reached daily limit of maximum ') . config('app.settings.email_limit', 5) . __(' temp mail addresses.')); + } + if (!$this->validateCaptcha()) { + return $this->showAlert('error', __('Invalid Captcha. Please try again')); + } + $this->email = ZEmail::generateRandomEmail(); + $this->redirect(route('mailbox')); + } + + public function tempgmail() { + if (!$this->checkEmailLimit()) { + return $this->showAlert('error', __('You have reached daily limit of maximum ') . config('app.settings.email_limit', 5) . __(' temp mail addresses.')); + } + if (!$this->validateCaptcha()) { + return $this->showAlert('error', __('Invalid Captcha. Please try again')); + } + $this->email = ZEmail::generateRandomGmail(); + $this->redirect(route('mailbox')); + } + + public function deleteEmail() { + ZEmail::removeEmail($this->email); + if (count($this->emails) == 1 && config('app.settings.after_last_email_delete') == 'redirect_to_homepage') { + return redirect()->route('home'); + } + $this->email = ZEmail::getEmail(true); + $this->emails = ZEmail::getEmails(); + return redirect()->route('mailbox'); + } + + public function render() { + if (count($this->emails) >= intval(config('app.settings.email_limit', 5))) { + for ($i = 0; $i < (count($this->emails) - intval(config('app.settings.email_limit', 5))); $i++) { + ZEmail::removeEmail($this->emails[$i]); + } + $this->emails = ZEmail::getEmails(); + ZEmail::setEmail($this->email); + } + return view('livewire.frontend.action'); + } + + /** + * Private Functions + */ + + private function showAlert($type, $message) { + $this->dispatchBrowserEvent('showAlert', ['type' => $type, 'message' => $message]); + } + + /** + * Don't allow used email + */ + private function checkUsedEmail() { + if (config('app.settings.disable_used_email', false)) { + $check = Log::where('email', $this->user . '@' . $this->domain)->where('ip', '<>', request()->ip())->count(); + if ($check > 0) { + return false; + } + return true; + } + return true; + } + + /** + * Validate Captcha + */ + private function validateCaptcha() { + if (config('app.settings.captcha') == 'hcaptcha') { + $response = Http::asForm()->post('https://hcaptcha.com/siteverify', [ + 'response' => $this->captcha, + 'secret' => config('app.settings.hcaptcha.secret_key') + ])->object(); + return $response->success; + } else if (config('app.settings.captcha') == 'recaptcha2') { + $response = Http::asForm()->post('https://www.google.com/recaptcha/api/siteverify', [ + 'response' => $this->captcha, + 'secret' => config('app.settings.recaptcha2.secret_key') + ])->object(); + return $response->success; + } + return true; + } + + /** + * Check if the user is crossing email limit + */ + private function checkEmailLimit() { + $logs = Log::select('ip', 'email')->where('ip', request()->ip())->where('created_at', '>', Carbon::now()->subDay())->groupBy('email')->groupBy('ip')->get(); + if (count($logs) >= config('app.settings.email_limit', 5)) { + return false; + } + return true; + } + + /** + * Check if Username already consist of Domain + */ + private function checkDomainInUsername() { + $parts = explode('@', $this->user); + if (isset($parts[1])) { + if (in_array($parts[1], $this->domains)) { + $this->domain = $parts[1]; + } + $this->user = $parts[0]; + } + } + + /** + * Validate if Domain in Email Exist + */ + private function validateDomainInEmail() { + $data = explode('@', $this->email); + if (isset($data[1])) { + $domain = $data[1]; + $domains = config('app.settings.domains'); + if (!in_array($domain, $domains)) { + $key = array_search($this->email, $this->emails); + TMail::removeEmail($this->email); + if ($key == 0 && count($this->emails) == 1 && config('app.settings.after_last_email_delete') == 'redirect_to_homepage') { + return redirect()->route('home'); + } else { + return redirect()->route('mailbox'); + } + } + } + } + +} diff --git a/app/Livewire/Frontend/App.php b/app/Livewire/Frontend/App.php new file mode 100644 index 0000000..66f643d --- /dev/null +++ b/app/Livewire/Frontend/App.php @@ -0,0 +1,109 @@ + 'fetch', 'syncEmail']; + + public function mount() + { + $this->email = ZEmail::getEmails(); + $this->initial = false; + } + + public function syncEmail($email) { + $this->email = $email; + } + + public function fetch() { + try { + $count = count($this->messages); + $responses = []; + if (config('app.beta_feature') || !json_decode(config('app.settings.imap_settings'))->cc_check) { + $responses = [ + 'to' => ZEmail::getMessages($this->email, 'to', $this->deleted), + 'cc' => [ + 'data' => [], + 'notifications' => [] + ] + ]; + } else { + $responses = [ + 'to' => ZEmail::getMessages($this->email, 'to', $this->deleted), + 'cc' => ZEmail::getMessages($this->email, 'cc', $this->deleted) + ]; + } + $this->deleted = []; + $this->messages = array_merge($responses['to']['data'], $responses['cc']['data']); + $notifications = array_merge($responses['to']['notifications'], $responses['cc']['notifications']); + if (count($notifications)) { + if ($this->overflow == false && count($this->messages) == $count) { + $this->overflow = true; + } + } else { + $this->overflow = false; + } + foreach ($notifications as $notification) { + $this->dispatchBrowserEvent('showNewMailNotification', $notification); + } + ZEmail::incrementMessagesStats(count($notifications)); + } catch (\Exception $e) { + if (Auth::check() && Auth::user()->level == 9) { + $this->error = $e->getMessage(); + } else { + $this->error = 'Not able to connect to Mail Server'; + } + } + $this->dispatchBrowserEvent('stopLoader'); + $this->dispatchBrowserEvent('loadDownload'); + $this->initial = true; + } + + public function delete($messageId) { + if (config('app.beta_feature')) { + Message::find($messageId)->delete(); + } + $this->deleted[] = $messageId; + foreach ($this->messages as $key => $message) { + if ($message['id'] == $messageId) { + $directory = './tmp/attachments/' . $messageId; + $this->rrmdir($directory); + unset($this->messages[$key]); + } + } + } + + public function render() + { + return view('livewire.frontend.app'); + } + private function rrmdir($dir): void + { + if (is_dir($dir)) { + $objects = scandir($dir); + foreach ($objects as $object) { + if ($object != "." && $object != "..") { + if (is_dir($dir . DIRECTORY_SEPARATOR . $object) && !is_link($dir . "/" . $object)) + $this->rrmdir($dir . DIRECTORY_SEPARATOR . $object); + else + unlink($dir . DIRECTORY_SEPARATOR . $object); + } + } + rmdir($dir); + } + } + +} diff --git a/app/Livewire/Frontend/Email.php b/app/Livewire/Frontend/Email.php new file mode 100644 index 0000000..22d34f8 --- /dev/null +++ b/app/Livewire/Frontend/Email.php @@ -0,0 +1,65 @@ + 'syncEmail', 'getEmail' => 'generateEmail']; + + public function mount(): void + { + $this->email = ZEmail::getEmail(); + $this->emails = ZEmail::getEmails(); + $this->initial = false; + $this->checkMultipleEmails(); + } + + private function checkMultipleEmails(): void + { + if (count($this->emails) == 0) { + $this->emails = [$this->email]; + } + if (count($this->emails) > 1) { + $this->list = true; + } else { + $this->list = false; + } + } + + public function switchEmail($email): void + { + ZEmail::setEmail($email); + $this->email = $email; + $this->dispatch('updateEmail'); + } + + public function syncEmail(): void + { + $this->email = ZEmail::getEmail(); + $this->emails = ZEmail::getEmails(); + if (count($this->emails) == 0) { + $this->dispatch('getEmail'); + } + $this->checkMultipleEmails(); + } + + public function generateEmail(): void + { + if ($this->email == null) { + ZEmail::generateRandomEmail(); + } + $this->checkMultipleEmails(); + $this->dispatch('updateEmail'); + } + + public function render() + { + return view('livewire.frontend.email')->with(['email' => $this->email, 'emails' => $this->emails, 'initial' => $this->initial, 'type' => $this->type, 'list' => $this->list]); + } +} diff --git a/app/Livewire/Home.php b/app/Livewire/Home.php new file mode 100644 index 0000000..0374ba4 --- /dev/null +++ b/app/Livewire/Home.php @@ -0,0 +1,13 @@ +created_at; - $obj['date'] = $message->created_at->format(json_decode(config('app.settings.configuration_settings'))->date_format, 'd M Y h:i A'); + $obj['date'] = $message->created_at->format(json_decode(config('app.settings.configuration_settings'))->date_format ?? 'd M Y h:i A'); $obj['datediff'] = $message->created_at->diffForHumans(); $obj['id'] = $message->id; $obj['content'] = $content; @@ -105,4 +110,239 @@ class Message extends Model } return $response; } + + public static function fetchMessages($email, $type = 'to', $deleted = []): array + { + $allowed = explode(',', 'doc,docx,xls,xlsx,ppt,pptx,xps,pdf,dxf,ai,psd,eps,ps,svg,ttf,zip,rar,tar,gzip,mp3,mpeg,wav,ogg,jpeg,jpg,png,gif,bmp,tif,webm,mpeg4,3gpp,mov,avi,mpegs,wmv,flx,txt'); + $connection = ZEmail::connectMailBox(); + + $mailbox = $connection->getMailbox('INBOX'); + $search = new SearchExpression(); + if ($type == 'cc') { + $search->addCondition(new Cc($email)); + } else { + $search->addCondition(new To($email)); + } + $search->addCondition(new Since((new \DateTime('-1 day')))); + $messages = $mailbox->getMessages($search, \SORTDATE, true); + $limit = json_decode(config('app.settings.configuration_settings'))->fetch_messages_limit ?? 15; + $count = 1; + $response = [ + 'data' => [], + 'notifications' => [] + ]; + + foreach ($messages as $message) { + if (in_array($message->getNumber(), $deleted)) { + $message->delete(); + continue; + } + $blocked = false; + $sender = $message->getFrom(); + $date = $message->getDate(); + if (!$date) { + $date = new \DateTime(); + if ($message->getHeaders()->get('udate')) { + $date->setTimestamp($message->getHeaders()->get('udate')); + } + } + $datediff = new Carbon($date); + $content = ''; + $html = $message->getBodyHtml(); + if ($html) { + $content = str_replace('getBodyText(); + $content = str_replace('', $text)); + } + if (json_decode(config('app.settings.configuration_settings'))->enable_masking_external_link) { + $content = str_replace('href="', 'href="http://href.li/?', $content); + } + $obj = []; + $obj['subject'] = $message->getSubject(); + $obj['sender_name'] = $sender->getName(); + $obj['sender_email'] = $sender->getAddress(); + $obj['timestamp'] = $message->getDate(); + $obj['date'] = $date->format(json_decode(config('app.settings.configuration_settings'))->date_format ?? 'd M Y h:i A'); + $obj['datediff'] = $datediff->diffForHumans(); + $obj['id'] = $message->getNumber(); + $obj['content'] = $content; + $obj['attachments'] = []; + //Checking if Sender is Blocked + $domain = explode('@', $obj['sender_email'])[1]; + $blocked = in_array($domain, json_decode(config('app.settings.configuration_settings'))->blocked_domains); + if ($blocked) { + $obj['subject'] = __('Blocked'); + $obj['content'] = __('Emails from') . ' ' . $domain . ' ' . __('are blocked by Admin'); + } + if ($message->hasAttachments() && !$blocked) { + $attachments = $message->getAttachments(); + $directory = './tmp/attachments/' . $obj['id'] . '/'; + is_dir($directory) || mkdir($directory, 0777, true); + foreach ($attachments as $attachment) { + $filenameArray = explode('.', $attachment->getFilename()); + $extension = $filenameArray[count($filenameArray) - 1]; + if (in_array($extension, $allowed)) { + if (!file_exists($directory . $attachment->getFilename())) { + file_put_contents( + $directory . $attachment->getFilename(), + $attachment->getDecodedContent() + ); + } + if ($attachment->getFilename() !== 'undefined') { + $url = config('app.settings.app_base_url') . str_replace('./', '/', $directory . $attachment->getFilename()); + $structure = $attachment->getStructure(); + if (isset($structure->id) && str_contains($obj['content'], trim($structure->id, '<>'))) { + $obj['content'] = str_replace('cid:' . trim($structure->id, '<>'), $url, $obj['content']); + } + $obj['attachments'][] = [ + 'file' => $attachment->getFilename(), + 'url' => $url + ]; + } + } + } + } + $response['data'][] = $obj; + if (!$message->isSeen()) { + $response['notifications'][] = [ + 'subject' => $obj['subject'], + 'sender_name' => $obj['sender_name'], + 'sender_email' => $obj['sender_email'] + ]; + if (config('app.zemail_log')) { + file_put_contents(storage_path('logs/zemail.csv'), request()->ip() . "," . date("Y-m-d h:i:s a") . "," . $obj['sender_email'] . "," . $email . PHP_EOL, FILE_APPEND); + } + } + $message->markAsSeen(); + if (++$count > $limit) { + break; + } + } + + $response['data'] = array_reverse($response['data']); + $connection->expunge(); + return $response; + } + +// public static function fetchMessages($email, $type = 'to', $deleted = []): array +// { +// $startTime = microtime(true); +// $allowed = explode(',', 'doc,docx,xls,xlsx,ppt,pptx,xps,pdf,dxf,ai,psd,eps,ps,svg,ttf,zip,rar,tar,gzip,mp3,mpeg,wav,ogg,jpeg,jpg,png,gif,bmp,tif,webm,mpeg4,3gpp,mov,avi,mpegs,wmv,flx,txt'); +// $connection = ZEmail::connectMailBox(); +// +// $mailbox = $connection->getMailbox('INBOX'); +// $search = new SearchExpression(); +// if ($type == 'cc') { +// $search->addCondition(new Cc($email)); +// } else { +// $search->addCondition(new To($email)); +// } +// $search->addCondition(new Since((new \DateTime('-1 day')))); +// $stepStart = microtime(true); +// $messages = $mailbox->getMessages($search, \SORTDATE, true); +// \Log::info("1111 messages took: " . (microtime(true) - $stepStart)); +// +// $limit = json_decode(config('app.settings.configuration_settings'))->fetch_messages_limit ?? 15; +// $count = 1; +// $response = [ +// 'data' => [], +// 'notifications' => [] +// ]; +// +// foreach ($messages as $message) { +// if (in_array($message->getNumber(), $deleted)) { +// $message->delete(); +// continue; +// } +// $blocked = false; +// $sender = $message->getFrom(); +// $date = $message->getDate(); +// if (!$date) { +// $date = new \DateTime(); +// if ($message->getHeaders()->get('udate')) { +// $date->setTimestamp($message->getHeaders()->get('udate')); +// } +// } +// $datediff = new Carbon($date); +// $content = ''; +// $html = $message->getBodyHtml(); +// if ($html) { +// $content = str_replace('getBodyText(); +// $content = str_replace('', $text)); +// } +// if (json_decode(config('app.settings.configuration_settings'))->enable_masking_external_link) { +// $content = str_replace('href="', 'href="http://href.li/?', $content); +// } +// $obj = []; +// $obj['subject'] = $message->getSubject(); +// $obj['sender_name'] = $sender->getName(); +// $obj['sender_email'] = $sender->getAddress(); +// $obj['timestamp'] = $message->getDate(); +// $obj['date'] = $date->format(json_decode(config('app.settings.configuration_settings'))->date_format ?? 'd M Y h:i A'); +// $obj['datediff'] = $datediff->diffForHumans(); +// $obj['id'] = $message->getNumber(); +// $obj['content'] = $content; +// $obj['attachments'] = []; +// //Checking if Sender is Blocked +// $domain = explode('@', $obj['sender_email'])[1]; +// $blocked = in_array($domain, json_decode(config('app.settings.configuration_settings'))->blocked_domains); +// if ($blocked) { +// $obj['subject'] = __('Blocked'); +// $obj['content'] = __('Emails from') . ' ' . $domain . ' ' . __('are blocked by Admin'); +// } +// if ($message->hasAttachments() && !$blocked) { +// $attachments = $message->getAttachments(); +// $directory = './tmp/attachments/' . $obj['id'] . '/'; +// is_dir($directory) || mkdir($directory, 0777, true); +// foreach ($attachments as $attachment) { +// $filenameArray = explode('.', $attachment->getFilename()); +// $extension = $filenameArray[count($filenameArray) - 1]; +// if (in_array($extension, $allowed)) { +// if (!file_exists($directory . $attachment->getFilename())) { +// file_put_contents( +// $directory . $attachment->getFilename(), +// $attachment->getDecodedContent() +// ); +// } +// if ($attachment->getFilename() !== 'undefined') { +// $url = config('app.settings.app_base_url') . str_replace('./', '/', $directory . $attachment->getFilename()); +// $structure = $attachment->getStructure(); +// if (isset($structure->id) && str_contains($obj['content'], trim($structure->id, '<>'))) { +// $obj['content'] = str_replace('cid:' . trim($structure->id, '<>'), $url, $obj['content']); +// } +// $obj['attachments'][] = [ +// 'file' => $attachment->getFilename(), +// 'url' => $url +// ]; +// } +// } +// } +// } +// $response['data'][] = $obj; +// if (!$message->isSeen()) { +// $response['notifications'][] = [ +// 'subject' => $obj['subject'], +// 'sender_name' => $obj['sender_name'], +// 'sender_email' => $obj['sender_email'] +// ]; +// if (config('app.zemail_log')) { +// file_put_contents(storage_path('logs/zemail.csv'), request()->ip() . "," . date("Y-m-d h:i:s a") . "," . $obj['sender_email'] . "," . $email . PHP_EOL, FILE_APPEND); +// } +// } +// $message->markAsSeen(); +// if (++$count > $limit) { +// break; +// } +// } +// +// $response['data'] = array_reverse($response['data']); +// $connection->expunge(); +// $endTime = microtime(true); +// $executionTime = $endTime - $startTime; +// \Log::info("getMessages execution time: {$executionTime} seconds"); +// return $response; +// } } diff --git a/app/Models/ZEmail.php b/app/Models/ZEmail.php index a971124..910cf9f 100644 --- a/app/Models/ZEmail.php +++ b/app/Models/ZEmail.php @@ -3,6 +3,7 @@ namespace App\Models; use Carbon\Carbon; +use Ddeboer\Imap\Search\Date\Since; use Ddeboer\Imap\Search\Email\Cc; use Ddeboer\Imap\Search\Email\To; use Ddeboer\Imap\SearchExpression; @@ -38,112 +39,7 @@ class ZEmail extends Model if (config('app.beta_feature')) { return Message::getMessages($email); } - $allowed = explode(',', 'doc,docx,xls,xlsx,ppt,pptx,xps,pdf,dxf,ai,psd,eps,ps,svg,ttf,zip,rar,tar,gzip,mp3,mpeg,wav,ogg,jpeg,jpg,png,gif,bmp,tif,webm,mpeg4,3gpp,mov,avi,mpegs,wmv,flx,txt'); - $connection = ZEmail::connectMailBox(); - $mailbox = $connection->getMailbox('INBOX'); - $search = new SearchExpression(); - if ($type == 'cc') { - $search->addCondition(new Cc($email)); - } else { - $search->addCondition(new To($email)); - } - $messages = $mailbox->getMessages($search, \SORTDATE, true); - $limit = json_decode(config('app.settings.configuration_settings'))->fetch_messages_limit ?? 15; - $count = 1; - $response = [ - 'data' => [], - 'notifications' => [] - ]; - foreach ($messages as $message) { - if (in_array($message->getNumber(), $deleted)) { - $message->delete(); - continue; - } - $blocked = false; - $sender = $message->getFrom(); - $date = $message->getDate(); - if (!$date) { - $date = new \DateTime(); - if ($message->getHeaders()->get('udate')) { - $date->setTimestamp($message->getHeaders()->get('udate')); - } - } - $datediff = new Carbon($date); - $content = ''; - $html = $message->getBodyHtml(); - if ($html) { - $content = str_replace('getBodyText(); - $content = str_replace('', $text)); - } - if (json_decode(config('app.settings.configuration_settings'))->enable_masking_external_link) { - $content = str_replace('href="', 'href="http://href.li/?', $content); - } - $obj = []; - $obj['subject'] = $message->getSubject(); - $obj['sender_name'] = $sender->getName(); - $obj['sender_email'] = $sender->getAddress(); - $obj['timestamp'] = $message->getDate(); - $obj['date'] = $date->format(json_decode(config('app.settings.configuration_settings'))->date_format, 'd M Y h:i A'); - $obj['datediff'] = $datediff->diffForHumans(); - $obj['id'] = $message->getNumber(); - $obj['content'] = $content; - $obj['attachments'] = []; - //Checking if Sender is Blocked - $domain = explode('@', $obj['sender_email'])[1]; - $blocked = in_array($domain, json_decode(config('app.settings.configuration_settings'))->blocked_domains); - if ($blocked) { - $obj['subject'] = __('Blocked'); - $obj['content'] = __('Emails from') . ' ' . $domain . ' ' . __('are blocked by Admin'); - } - if ($message->hasAttachments() && !$blocked) { - $attachments = $message->getAttachments(); - $directory = './tmp/attachments/' . $obj['id'] . '/'; - is_dir($directory) || mkdir($directory, 0777, true); - foreach ($attachments as $attachment) { - $filenameArray = explode('.', $attachment->getFilename()); - $extension = $filenameArray[count($filenameArray) - 1]; - if (in_array($extension, $allowed)) { - if (!file_exists($directory . $attachment->getFilename())) { - file_put_contents( - $directory . $attachment->getFilename(), - $attachment->getDecodedContent() - ); - } - if ($attachment->getFilename() !== 'undefined') { - $url = config('app.settings.app_base_url') . str_replace('./', '/', $directory . $attachment->getFilename()); - $structure = $attachment->getStructure(); - if (isset($structure->id) && str_contains($obj['content'], trim($structure->id, '<>'))) { - $obj['content'] = str_replace('cid:' . trim($structure->id, '<>'), $url, $obj['content']); - } - $obj['attachments'][] = [ - 'file' => $attachment->getFilename(), - 'url' => $url - ]; - } - } - } - } - $response['data'][] = $obj; - if (!$message->isSeen()) { - $response['notifications'][] = [ - 'subject' => $obj['subject'], - 'sender_name' => $obj['sender_name'], - 'sender_email' => $obj['sender_email'] - ]; - if (config('app.zemail_log')) { - file_put_contents(storage_path('logs/zemail.csv'), request()->ip() . "," . date("Y-m-d h:i:s a") . "," . $obj['sender_email'] . "," . $email . PHP_EOL, FILE_APPEND); - } - } - $message->markAsSeen(); - if (++$count > $limit) { - break; - } - } - $response['data'] = array_reverse($response['data']); - $connection->expunge(); - return $response; + return Message::fetchMessages($email, $type, $deleted); } public static function deleteMessage($id): void diff --git a/composer.json b/composer.json index 03b7421..f51eba3 100644 --- a/composer.json +++ b/composer.json @@ -11,6 +11,7 @@ "filament/filament": "3.3", "laravel/framework": "^12.0", "laravel/tinker": "^2.10.1", + "livewire/flux": "^2.1", "livewire/livewire": "^3.6" }, "require-dev": { diff --git a/composer.lock b/composer.lock index c7f2dd0..2a4065e 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": "3c178f04aa87a34364e767ad999d5889", + "content-hash": "8a5cd9a0ccf67c460d95ecb968192ef2", "packages": [ { "name": "anourvalar/eloquent-serialize", @@ -3143,6 +3143,69 @@ ], "time": "2024-12-08T08:18:47+00:00" }, + { + "name": "livewire/flux", + "version": "v2.1.4", + "source": { + "type": "git", + "url": "https://github.com/livewire/flux.git", + "reference": "a19709fc94f5a1b795ce24ad42662bd398c19371" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/livewire/flux/zipball/a19709fc94f5a1b795ce24ad42662bd398c19371", + "reference": "a19709fc94f5a1b795ce24ad42662bd398c19371", + "shasum": "" + }, + "require": { + "illuminate/console": "^10.0|^11.0|^12.0", + "illuminate/support": "^10.0|^11.0|^12.0", + "illuminate/view": "^10.0|^11.0|^12.0", + "laravel/prompts": "^0.1|^0.2|^0.3", + "livewire/livewire": "^3.5.19", + "php": "^8.1", + "symfony/console": "^6.0|^7.0" + }, + "type": "library", + "extra": { + "laravel": { + "aliases": { + "Flux": "Flux\\Flux" + }, + "providers": [ + "Flux\\FluxServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Flux\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "proprietary" + ], + "authors": [ + { + "name": "Caleb Porzio", + "email": "calebporzio@gmail.com" + } + ], + "description": "The official UI component library for Livewire.", + "keywords": [ + "components", + "flux", + "laravel", + "livewire", + "ui" + ], + "support": { + "issues": "https://github.com/livewire/flux/issues", + "source": "https://github.com/livewire/flux/tree/v2.1.4" + }, + "time": "2025-04-14T11:59:19+00:00" + }, { "name": "livewire/livewire", "version": "v3.6.3", diff --git a/public/images/logo.webp b/public/images/logo.webp new file mode 100644 index 0000000000000000000000000000000000000000..942d56c42887c50ae0e9f3675fd406e245160400 GIT binary patch literal 4694 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 literal 0 HcmV?d00001 diff --git a/public/images/user.webp b/public/images/user.webp new file mode 100644 index 0000000000000000000000000000000000000000..7c6ecbaa638e3919cb147e55b3cc49f55e732def GIT binary patch literal 13056 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 B&949e literal 0 HcmV?d00001 diff --git a/public/images/zemail-logo-dark.webp b/public/images/zemail-logo-dark.webp new file mode 100644 index 0000000000000000000000000000000000000000..f124840b51d0c521a5c7d13d983a73367f06ebfd GIT binary patch literal 17258 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 J?@R;ue*oAc8ruK> literal 0 HcmV?d00001 diff --git a/resources/css/app.css b/resources/css/app.css index 3e6abea..be63e5f 100644 --- a/resources/css/app.css +++ b/resources/css/app.css @@ -1,11 +1,52 @@ @import 'tailwindcss'; + +@import '../../vendor/livewire/flux/dist/flux.css'; @source '../../vendor/laravel/framework/src/Illuminate/Pagination/resources/views/*.blade.php'; @source '../../storage/framework/views/*.php'; @source '../**/*.blade.php'; @source '../**/*.js'; + +@custom-variant dark (&:where(.dark, .dark *)); + +/*@theme {*/ +/* --font-sans: 'Instrument Sans', ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',*/ +/* 'Segoe UI Symbol', 'Noto Color Emoji';*/ +/*}*/ + @theme { - --font-sans: 'Instrument Sans', ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', - 'Segoe UI Symbol', 'Noto Color Emoji'; + --font-sans: Inter, sans-serif; } + +/* Re-assign Flux's gray of choice... */ +@theme { + --color-zinc-50: var(--color-gray-50); + --color-zinc-100: var(--color-gray-100); + --color-zinc-200: var(--color-gray-200); + --color-zinc-300: var(--color-gray-300); + --color-zinc-400: var(--color-gray-400); + --color-zinc-500: var(--color-gray-500); + --color-zinc-600: var(--color-gray-600); + --color-zinc-700: var(--color-gray-800); + --color-zinc-800: var(--color-gray-800); + --color-zinc-900: var(--color-gray-900); + --color-zinc-950: var(--color-gray-950); + /*--color-white: var(--color-gray-100);*/ +} + +@theme { + --color-accent: var(--color-gray-900); + --color-accent-content: var(--color-gray-900); + --color-accent-foreground: var(--color-white); +} + +@layer theme { + .dark { + --color-accent: var(--color-white); + --color-accent-content: var(--color-white); + --color-accent-foreground: var(--color-gray-900); + } +} + + diff --git a/resources/css/boil.css b/resources/css/boil.css index 44e66b5..345d9e2 100644 --- a/resources/css/boil.css +++ b/resources/css/boil.css @@ -1,3 +1,60 @@ -.art { - color: orange; +.inbox-btn { + background-color: #F14743; + color: white; + transition: background-color 0.3s ease; +} + +.inbox-btn:hover { + background-color: #f72a25; +} + +.btn-primary { + color: white; + background-color: #4361ee; +} + +.btn-warning { + color: white; + background-color: #e2a03f; +} +.btn-success { + background-color: #00AB55; + color: white; +} +.inbox-list { + margin-bottom: 10px; +} +.inbox-new { + background-color: #00AB55; +} + +.iframe-min-height { + min-height: 70vh; +} +@keyframes slide-in { + from { + transform: translateY(-1rem); + opacity: 0; + } + to { + transform: translateY(0); + opacity: 1; + } +} + +@keyframes progress { + from { + width: 100%; + } + to { + width: 0%; + } +} + +.animate-slide-in { + animation: slide-in 0.3s ease-out; +} + +.animate-progress { + animation: progress 4s linear forwards; } diff --git a/resources/js/boil.js b/resources/js/boil.js new file mode 100644 index 0000000..3470bab --- /dev/null +++ b/resources/js/boil.js @@ -0,0 +1,69 @@ +document.addEventListener('DOMContentLoaded', () => { + if (window.Livewire && typeof window.Livewire.dispatch === 'function') { + setTimeout(() => { + Livewire.dispatch('getEmail'); + }, 2000); + + document.addEventListener('closeModal', () => { + document.querySelectorAll('dialog[data-modal]').forEach(dialog => { + if (typeof dialog.close === 'function') { + dialog.close(); + console.log(`Closed dialog with data-modal="${dialog.getAttribute('data-modal')}"`); + } + }); + }); + + } else { + console.warn('Livewire is not loaded yet.'); + } +}); + + +function showToast({ type = 'success', message = '' }) { +const container = document.getElementById('toast-container'); + +const colors = { +success: { +icon: 'text-green-500 bg-green-100 dark:bg-green-800 dark:text-green-200', +svg: ``, +}, +error: { +icon: 'text-red-500 bg-red-100 dark:bg-red-800 dark:text-red-200', +svg: ``, +} +}; + +const toast = document.createElement('div'); +toast.className = `flex items-center w-full max-w-xs p-4 text-gray-500 bg-white rounded-lg shadow dark:text-gray-400 dark:bg-gray-800`; +toast.setAttribute('role', 'alert'); + +toast.innerHTML = ` +
+ ${colors[type].svg} +
+
${message}
+
+ + `; +container.appendChild(toast); + +setTimeout(() => { +toast.remove(); +}, 4000); +} + +function handleDispatches(dispatches) { +dispatches.forEach(dispatch => { + if (dispatch.name === "showAlert") { + const params = dispatch.params[0]; + showToast(params); + } +}); +} +window.addEventListener("showAlert", (event) => { + const detail = event.detail[0]; + showToast(detail); +}); diff --git a/resources/views/components/layouts/app.blade.php b/resources/views/components/layouts/app.blade.php new file mode 100644 index 0000000..8d20aa8 --- /dev/null +++ b/resources/views/components/layouts/app.blade.php @@ -0,0 +1,129 @@ + + + + + + + {{ $title ?? 'Page Title' }} + @if (file_exists(public_path('build/manifest.json')) || file_exists(public_path('hot'))) + @vite(['resources/css/app.css', 'resources/css/boil.css', 'resources/js/app.js', 'resources/js/boil.js']) + @endif + + @fluxAppearance + + + + +
+ logo + + +
+ + + Inbox + Refresh + + sideAds + + + API + FAQ + Privacy + Feedback + Contacts + + +

© {{ config('app.settings.app_name') }}

+
+ + + + + + + + + + + + + + + + + You are signed in as: +
+ +
+ +
+ + Create Account + + + + + + +
+
+
+
+ +
+ + + +
+
+ Generate Your Temporary Email +
+ + + + + + +
+
+ +
+
+ +
+
+ +
+
+ + +
+
+ Delete account? + +

You're about to delete this account.

+
+
+
+ + + Cancel + + +
+
+
+ + + {{ $slot }} + + + +
+ +
+ + @fluxScripts + + diff --git a/resources/views/filament/pages/setting.blade.php b/resources/views/filament/pages/setting.blade.php deleted file mode 100644 index cc61477..0000000 --- a/resources/views/filament/pages/setting.blade.php +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/resources/views/flux/icon/circle-user-round.blade.php b/resources/views/flux/icon/circle-user-round.blade.php new file mode 100644 index 0000000..b977980 --- /dev/null +++ b/resources/views/flux/icon/circle-user-round.blade.php @@ -0,0 +1,43 @@ +{{-- Credit: Lucide (https://lucide.dev) --}} + +@props([ + 'variant' => 'outline', +]) + +@php +if ($variant === 'solid') { + throw new \Exception('The "solid" variant is not supported in Lucide.'); +} + +$classes = Flux::classes('shrink-0') + ->add(match($variant) { + 'outline' => '[:where(&)]:size-6', + 'solid' => '[:where(&)]:size-6', + 'mini' => '[:where(&)]:size-5', + 'micro' => '[:where(&)]:size-4', + }); + +$strokeWidth = match ($variant) { + 'outline' => 2, + 'mini' => 2.25, + 'micro' => 2.5, +}; +@endphp + +class($classes) }} + data-flux-icon + xmlns="http://www.w3.org/2000/svg" + viewBox="0 0 24 24" + fill="none" + stroke="currentColor" + stroke-width="{{ $strokeWidth }}" + stroke-linecap="round" + stroke-linejoin="round" + aria-hidden="true" + data-slot="icon" +> + + + + diff --git a/resources/views/flux/icon/download.blade.php b/resources/views/flux/icon/download.blade.php new file mode 100644 index 0000000..1e455c1 --- /dev/null +++ b/resources/views/flux/icon/download.blade.php @@ -0,0 +1,43 @@ +{{-- Credit: Lucide (https://lucide.dev) --}} + +@props([ + 'variant' => 'outline', +]) + +@php +if ($variant === 'solid') { + throw new \Exception('The "solid" variant is not supported in Lucide.'); +} + +$classes = Flux::classes('shrink-0') + ->add(match($variant) { + 'outline' => '[:where(&)]:size-6', + 'solid' => '[:where(&)]:size-6', + 'mini' => '[:where(&)]:size-5', + 'micro' => '[:where(&)]:size-4', + }); + +$strokeWidth = match ($variant) { + 'outline' => 2, + 'mini' => 2.25, + 'micro' => 2.5, +}; +@endphp + +class($classes) }} + data-flux-icon + xmlns="http://www.w3.org/2000/svg" + viewBox="0 0 24 24" + fill="none" + stroke="currentColor" + stroke-width="{{ $strokeWidth }}" + stroke-linecap="round" + stroke-linejoin="round" + aria-hidden="true" + data-slot="icon" +> + + + + diff --git a/resources/views/flux/icon/file-down.blade.php b/resources/views/flux/icon/file-down.blade.php new file mode 100644 index 0000000..ee11c2e --- /dev/null +++ b/resources/views/flux/icon/file-down.blade.php @@ -0,0 +1,44 @@ +{{-- Credit: Lucide (https://lucide.dev) --}} + +@props([ + 'variant' => 'outline', +]) + +@php +if ($variant === 'solid') { + throw new \Exception('The "solid" variant is not supported in Lucide.'); +} + +$classes = Flux::classes('shrink-0') + ->add(match($variant) { + 'outline' => '[:where(&)]:size-6', + 'solid' => '[:where(&)]:size-6', + 'mini' => '[:where(&)]:size-5', + 'micro' => '[:where(&)]:size-4', + }); + +$strokeWidth = match ($variant) { + 'outline' => 2, + 'mini' => 2.25, + 'micro' => 2.5, +}; +@endphp + +class($classes) }} + data-flux-icon + xmlns="http://www.w3.org/2000/svg" + viewBox="0 0 24 24" + fill="none" + stroke="currentColor" + stroke-width="{{ $strokeWidth }}" + stroke-linecap="round" + stroke-linejoin="round" + aria-hidden="true" + data-slot="icon" +> + + + + + diff --git a/resources/views/flux/icon/file.blade.php b/resources/views/flux/icon/file.blade.php new file mode 100644 index 0000000..d906883 --- /dev/null +++ b/resources/views/flux/icon/file.blade.php @@ -0,0 +1,42 @@ +{{-- Credit: Lucide (https://lucide.dev) --}} + +@props([ + 'variant' => 'outline', +]) + +@php +if ($variant === 'solid') { + throw new \Exception('The "solid" variant is not supported in Lucide.'); +} + +$classes = Flux::classes('shrink-0') + ->add(match($variant) { + 'outline' => '[:where(&)]:size-6', + 'solid' => '[:where(&)]:size-6', + 'mini' => '[:where(&)]:size-5', + 'micro' => '[:where(&)]:size-4', + }); + +$strokeWidth = match ($variant) { + 'outline' => 2, + 'mini' => 2.25, + 'micro' => 2.5, +}; +@endphp + +class($classes) }} + data-flux-icon + xmlns="http://www.w3.org/2000/svg" + viewBox="0 0 24 24" + fill="none" + stroke="currentColor" + stroke-width="{{ $strokeWidth }}" + stroke-linecap="round" + stroke-linejoin="round" + aria-hidden="true" + data-slot="icon" +> + + + diff --git a/resources/views/flux/icon/mail-plus.blade.php b/resources/views/flux/icon/mail-plus.blade.php new file mode 100644 index 0000000..a8d8666 --- /dev/null +++ b/resources/views/flux/icon/mail-plus.blade.php @@ -0,0 +1,44 @@ +{{-- Credit: Lucide (https://lucide.dev) --}} + +@props([ + 'variant' => 'outline', +]) + +@php +if ($variant === 'solid') { + throw new \Exception('The "solid" variant is not supported in Lucide.'); +} + +$classes = Flux::classes('shrink-0') + ->add(match($variant) { + 'outline' => '[:where(&)]:size-6', + 'solid' => '[:where(&)]:size-6', + 'mini' => '[:where(&)]:size-5', + 'micro' => '[:where(&)]:size-4', + }); + +$strokeWidth = match ($variant) { + 'outline' => 2, + 'mini' => 2.25, + 'micro' => 2.5, +}; +@endphp + +class($classes) }} + data-flux-icon + xmlns="http://www.w3.org/2000/svg" + viewBox="0 0 24 24" + fill="none" + stroke="currentColor" + stroke-width="{{ $strokeWidth }}" + stroke-linecap="round" + stroke-linejoin="round" + aria-hidden="true" + data-slot="icon" +> + + + + + diff --git a/resources/views/flux/icon/mail.blade.php b/resources/views/flux/icon/mail.blade.php new file mode 100644 index 0000000..6d1583a --- /dev/null +++ b/resources/views/flux/icon/mail.blade.php @@ -0,0 +1,42 @@ +{{-- Credit: Lucide (https://lucide.dev) --}} + +@props([ + 'variant' => 'outline', +]) + +@php +if ($variant === 'solid') { + throw new \Exception('The "solid" variant is not supported in Lucide.'); +} + +$classes = Flux::classes('shrink-0') + ->add(match($variant) { + 'outline' => '[:where(&)]:size-6', + 'solid' => '[:where(&)]:size-6', + 'mini' => '[:where(&)]:size-5', + 'micro' => '[:where(&)]:size-4', + }); + +$strokeWidth = match ($variant) { + 'outline' => 2, + 'mini' => 2.25, + 'micro' => 2.5, +}; +@endphp + +class($classes) }} + data-flux-icon + xmlns="http://www.w3.org/2000/svg" + viewBox="0 0 24 24" + fill="none" + stroke="currentColor" + stroke-width="{{ $strokeWidth }}" + stroke-linecap="round" + stroke-linejoin="round" + aria-hidden="true" + data-slot="icon" +> + + + diff --git a/resources/views/flux/icon/refresh-cw.blade.php b/resources/views/flux/icon/refresh-cw.blade.php new file mode 100644 index 0000000..ae36ca2 --- /dev/null +++ b/resources/views/flux/icon/refresh-cw.blade.php @@ -0,0 +1,44 @@ +{{-- Credit: Lucide (https://lucide.dev) --}} + +@props([ + 'variant' => 'outline', +]) + +@php +if ($variant === 'solid') { + throw new \Exception('The "solid" variant is not supported in Lucide.'); +} + +$classes = Flux::classes('shrink-0') + ->add(match($variant) { + 'outline' => '[:where(&)]:size-6', + 'solid' => '[:where(&)]:size-6', + 'mini' => '[:where(&)]:size-5', + 'micro' => '[:where(&)]:size-4', + }); + +$strokeWidth = match ($variant) { + 'outline' => 2, + 'mini' => 2.25, + 'micro' => 2.5, +}; +@endphp + +class($classes) }} + data-flux-icon + xmlns="http://www.w3.org/2000/svg" + viewBox="0 0 24 24" + fill="none" + stroke="currentColor" + stroke-width="{{ $strokeWidth }}" + stroke-linecap="round" + stroke-linejoin="round" + aria-hidden="true" + data-slot="icon" +> + + + + + diff --git a/resources/views/flux/icon/sparkle.blade.php b/resources/views/flux/icon/sparkle.blade.php new file mode 100644 index 0000000..811b528 --- /dev/null +++ b/resources/views/flux/icon/sparkle.blade.php @@ -0,0 +1,41 @@ +{{-- Credit: Lucide (https://lucide.dev) --}} + +@props([ + 'variant' => 'outline', +]) + +@php +if ($variant === 'solid') { + throw new \Exception('The "solid" variant is not supported in Lucide.'); +} + +$classes = Flux::classes('shrink-0') + ->add(match($variant) { + 'outline' => '[:where(&)]:size-6', + 'solid' => '[:where(&)]:size-6', + 'mini' => '[:where(&)]:size-5', + 'micro' => '[:where(&)]:size-4', + }); + +$strokeWidth = match ($variant) { + 'outline' => 2, + 'mini' => 2.25, + 'micro' => 2.5, +}; +@endphp + +class($classes) }} + data-flux-icon + xmlns="http://www.w3.org/2000/svg" + viewBox="0 0 24 24" + fill="none" + stroke="currentColor" + stroke-width="{{ $strokeWidth }}" + stroke-linecap="round" + stroke-linejoin="round" + aria-hidden="true" + data-slot="icon" +> + + diff --git a/resources/views/livewire/email-inbox.blade.php b/resources/views/livewire/email-inbox.blade.php new file mode 100644 index 0000000..b73b28d --- /dev/null +++ b/resources/views/livewire/email-inbox.blade.php @@ -0,0 +1,51 @@ +
+
+ +
+

Your Disposable Email

+
+ + +
+
+ + +
+ @if(count($messages) > 0) + @foreach($messages as $message) +
+
+
+

{{ $message->subject }}

+

From: {{ $message->from }}

+

{{ $message->date }}

+
+ +
+
+ @endforeach + @else +
+ No messages yet. They will appear here automatically. +
+ @endif +
+
+ + + +
diff --git a/resources/views/livewire/email.blade.php b/resources/views/livewire/email.blade.php new file mode 100644 index 0000000..a8fb637 --- /dev/null +++ b/resources/views/livewire/email.blade.php @@ -0,0 +1,54 @@ +
+ + +
+
+

+ Resend Verification Email +

+
+
+ Download + Source + Print + Delete +
+
+
+
+
+
+
+ inbox-logo +
+
+
+ Fake-IT + register@receivefreesms.co.uk +
+ +
+
+
+
+ +
+
+
+ +
+
+
+ diff --git a/resources/views/livewire/frontend/action.blade.php b/resources/views/livewire/frontend/action.blade.php new file mode 100644 index 0000000..261a405 --- /dev/null +++ b/resources/views/livewire/frontend/action.blade.php @@ -0,0 +1,42 @@ + +@if($action == "random") + Random Email +@elseif($action == "gmail") + Disposable Gmail +@elseif($action == "delete") + Delete account +@elseif($action == "customEmail") +
+
+
+
+
+
+ +
+ +
+ + +
+
+
+
+ +
+
+ Cancel + Create Account +
+
+
+
+@endif +
diff --git a/resources/views/livewire/frontend/app.blade.php b/resources/views/livewire/frontend/app.blade.php new file mode 100644 index 0000000..a573dbb --- /dev/null +++ b/resources/views/livewire/frontend/app.blade.php @@ -0,0 +1,3 @@ +
+ {{-- Success is as dangerous as failure. --}} +
diff --git a/resources/views/livewire/frontend/email.blade.php b/resources/views/livewire/frontend/email.blade.php new file mode 100644 index 0000000..d6727a6 --- /dev/null +++ b/resources/views/livewire/frontend/email.blade.php @@ -0,0 +1,13 @@ + +@if($type === "header")

{{ $email ?? __('...') }}

+ @else{{ $email ?? __('...') }} + @if($list) + @foreach(array_reverse($emails) as $email_list_item) + + + {{ $email_list_item }} + + @endforeach + @endif + @endif +
diff --git a/resources/views/livewire/home.blade.php b/resources/views/livewire/home.blade.php new file mode 100644 index 0000000..7fbcbe9 --- /dev/null +++ b/resources/views/livewire/home.blade.php @@ -0,0 +1,11 @@ +
+Inbox +
+ @php + for ($i=0; $i<=10; $i++) { + @endphp + + @php + } + @endphp +
diff --git a/resources/views/livewire/inbox.blade.php b/resources/views/livewire/inbox.blade.php new file mode 100644 index 0000000..501990b --- /dev/null +++ b/resources/views/livewire/inbox.blade.php @@ -0,0 +1,48 @@ +
+
+
+
+
+ + inbox-logo + + +
+
+
+
+ Fake-IT +
+
+ + + + register@receivefreesms.co.uk
+
+ +
+
+
+ + + +
+
+
+
diff --git a/routes/web.php b/routes/web.php index f524a90..900f175 100644 --- a/routes/web.php +++ b/routes/web.php @@ -1,25 +1,13 @@ name('home'); +Route::get('/mailbox', Email::class)->name('mailbox'); +Route::get('/inbox', EmailInbox::class)->name('inbox'); -Route::get('ac', function () { - return json_decode(config('app.settings.configuration_settings'))->random_username_length_max ?? 0; - //return json_decode(config('app.settings.configuration_settings')) ?? []; -}); - -Route::get('bc', function (){ - return ZEmail::check(); -}); - -Route::get('zz', function (){ - try { - ZEmail::connectMailBox(); - } catch (Exception $ex) { - return $ex->getMessage(); - } -}); +//Route::get('/add/{email?}', [AppController::class, 'mailbox'])->name('mailbox'); diff --git a/vite.config.js b/vite.config.js index b12d7d2..bf9d553 100644 --- a/vite.config.js +++ b/vite.config.js @@ -5,7 +5,7 @@ import tailwindcss from '@tailwindcss/vite'; export default defineConfig({ plugins: [ laravel({ - input: ['resources/css/app.css', 'resources/css/boil.css', 'resources/js/app.js'], + input: ['resources/css/app.css', 'resources/css/boil.css', 'resources/js/app.js', 'resources/css/boil.js'], refresh: true, }), tailwindcss(),