├── LICENSE.md ├── composer.json ├── config └── mail-log.php ├── configure.php ├── database ├── factories │ ├── MailLogFactory.php │ └── ModelFactory.php ├── migrations │ └── 2025_02_06_000000_create_mail_logs_table.php └── seeders │ └── MailLogSeeder.php ├── dist ├── build │ ├── assets │ │ ├── MailIndex-DVYoo5uZ.js │ │ ├── MailShow-BdT1JXFW.js │ │ ├── app-aQLUJyJ9.js │ │ ├── app-gflgPwOp.css │ │ └── dayjs.min-NtYHfqg0.js │ └── manifest.json └── favicons │ ├── android-chrome-192x192.png │ ├── android-chrome-512x512.png │ ├── apple-touch-icon.png │ ├── browserconfig.xml │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── favicon.ico │ ├── mstile-150x150.png │ └── safari-pinned-tab.svg ├── docs └── images │ ├── mail-log-detail.webp │ └── mail-log-index.webp ├── resources └── views │ ├── .gitkeep │ └── app.blade.php ├── routes └── web.php └── src ├── Commands ├── DeleteAllMailLogsCommand.php └── DeleteOldMailLogsCommand.php ├── Http └── Controllers │ ├── AssetController.php │ └── MailController.php ├── Listeners ├── LogOutgoingMailListener.php └── UpdateEmailStatus.php ├── Middleware └── HandleInertiaRequests.php ├── Models └── MailLog.php └── Providers └── MailLogServiceProvider.php /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) :vendor_name 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gearbox-solutions/mail-log", 3 | "description": "Mail Logger", 4 | "keywords": [ 5 | "gearbox-solutions", 6 | "laravel", 7 | "mail-log" 8 | ], 9 | "homepage": "https://github.com/gearbox-solutions/mail-log", 10 | "license": "MIT", 11 | "authors": [ 12 | { 13 | "name": "David Nahodyl", 14 | "email": "david@gearboxgo.com" 15 | } 16 | ], 17 | "require": { 18 | "php": "^8.2", 19 | "illuminate/contracts": "^10.0||^11.0||^12.0", 20 | "inertiajs/inertia-laravel": "^2.0", 21 | "spatie/laravel-package-tools": "^1.16", 22 | "tightenco/ziggy": "^2.5" 23 | }, 24 | "require-dev": { 25 | "larastan/larastan": "^2.9", 26 | "laravel/pint": "^1.20", 27 | "nunomaduro/collision": "^8.1.1||^7.10.0", 28 | "orchestra/testbench": "^9.0.0||^8.22.0", 29 | "pestphp/pest": "^2.34", 30 | "pestphp/pest-plugin-arch": "^2.7", 31 | "pestphp/pest-plugin-laravel": "^2.3", 32 | "phpstan/extension-installer": "^1.3", 33 | "phpstan/phpstan-deprecation-rules": "^1.1", 34 | "phpstan/phpstan-phpunit": "^1.3", 35 | "spatie/laravel-ray": "^1.35" 36 | }, 37 | "autoload": { 38 | "psr-4": { 39 | "GearboxSolutions\\MailLog\\": "src/", 40 | "GearboxSolutions\\MailLog\\Database\\Factories\\": "database/factories/" 41 | } 42 | }, 43 | "autoload-dev": { 44 | "psr-4": { 45 | "GearboxSolutions\\MailLog\\Tests\\": "tests/", 46 | "GearboxSolutions\\MailLog\\Database\\Factories\\": "database/factories/", 47 | "GearboxSolutions\\MailLog\\Database\\Seeders\\": "database/seeders/", 48 | "Workbench\\App\\Console\\Commands\\": "workbench/app/Console/Commands/" 49 | } 50 | }, 51 | "scripts": { 52 | "post-autoload-dump": [ 53 | "@clear", 54 | "@prepare", 55 | "@composer run prepare" 56 | ], 57 | "clear": "@php vendor/bin/testbench package:purge-skeleton --ansi", 58 | "prepare": "@php vendor/bin/testbench package:discover --ansi", 59 | "build": "@php vendor/bin/testbench workbench:build --ansi", 60 | "start": [ 61 | "Composer\\Config::disableProcessTimeout", 62 | "@composer run build", 63 | "@php vendor/bin/testbench serve" 64 | ], 65 | "analyse": "vendor/bin/phpstan analyse", 66 | "test": "vendor/bin/pest", 67 | "test-coverage": "vendor/bin/pest --coverage", 68 | "format": "vendor/bin/pint", 69 | "serve": [ 70 | "Composer\\Config::disableProcessTimeout", 71 | "@build", 72 | "@php vendor/bin/testbench serve --ansi" 73 | ], 74 | "lint": [ 75 | "@php vendor/bin/pint --ansi", 76 | "@php vendor/bin/phpstan analyse --verbose --ansi" 77 | ] 78 | }, 79 | "config": { 80 | "sort-packages": true, 81 | "allow-plugins": { 82 | "pestphp/pest-plugin": true, 83 | "phpstan/extension-installer": true 84 | } 85 | }, 86 | "extra": { 87 | "laravel": { 88 | "providers": [ 89 | "GearboxSolutions\\MailLog\\Providers\\MailLogServiceProvider" 90 | ] 91 | } 92 | }, 93 | "minimum-stability": "dev", 94 | "prefer-stable": true 95 | } 96 | -------------------------------------------------------------------------------- /config/mail-log.php: -------------------------------------------------------------------------------- 1 | [AuthenticateSession::class], 16 | 17 | /* 18 | |-------------------------------------------------------------------------- 19 | | Database 20 | |-------------------------------------------------------------------------- 21 | | 22 | | Configure the database connection to use for storing mail log records 23 | | If this is null, it uses your default database connection 24 | | 25 | */ 26 | 'database' => null, 27 | ]; 28 | -------------------------------------------------------------------------------- /configure.php: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | $version) { 90 | if (in_array($name, $names, true)) { 91 | unset($data['require-dev'][$name]); 92 | } 93 | } 94 | 95 | file_put_contents(__DIR__.'/composer.json', json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)); 96 | } 97 | 98 | function remove_composer_script($scriptName) 99 | { 100 | $data = json_decode(file_get_contents(__DIR__.'/composer.json'), true); 101 | 102 | foreach ($data['scripts'] as $name => $script) { 103 | if ($scriptName === $name) { 104 | unset($data['scripts'][$name]); 105 | break; 106 | } 107 | } 108 | 109 | file_put_contents(__DIR__.'/composer.json', json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)); 110 | } 111 | 112 | function remove_readme_paragraphs(string $file): void 113 | { 114 | $contents = file_get_contents($file); 115 | 116 | file_put_contents( 117 | $file, 118 | preg_replace('/.*/s', '', $contents) ?: $contents 119 | ); 120 | } 121 | 122 | function safeUnlink(string $filename) 123 | { 124 | if (file_exists($filename) && is_file($filename)) { 125 | unlink($filename); 126 | } 127 | } 128 | 129 | function determineSeparator(string $path): string 130 | { 131 | return str_replace('/', DIRECTORY_SEPARATOR, $path); 132 | } 133 | 134 | function replaceForWindows(): array 135 | { 136 | return preg_split('/\\r\\n|\\r|\\n/', run('dir /S /B * | findstr /v /i .git\ | findstr /v /i vendor | findstr /v /i '.basename(__FILE__).' | findstr /r /i /M /F:/ ":author :vendor :package VendorName skeleton migration_table_name vendor_name vendor_slug author@domain.com"')); 137 | } 138 | 139 | function replaceForAllOtherOSes(): array 140 | { 141 | return explode(PHP_EOL, run('grep -E -r -l -i ":author|:vendor|:package|VendorName|skeleton|migration_table_name|vendor_name|vendor_slug|author@domain.com" --exclude-dir=vendor ./* ./.github/* | grep -v '.basename(__FILE__))); 142 | } 143 | 144 | function getGitHubApiEndpoint(string $endpoint): ?stdClass 145 | { 146 | try { 147 | $curl = curl_init("https://api.github.com/{$endpoint}"); 148 | curl_setopt_array($curl, [ 149 | CURLOPT_RETURNTRANSFER => true, 150 | CURLOPT_FOLLOWLOCATION => true, 151 | CURLOPT_HTTPGET => true, 152 | CURLOPT_HTTPHEADER => [ 153 | 'User-Agent: spatie-configure-script/1.0', 154 | ], 155 | ]); 156 | 157 | $response = curl_exec($curl); 158 | $statusCode = curl_getinfo($curl, CURLINFO_HTTP_CODE); 159 | 160 | curl_close($curl); 161 | 162 | if ($statusCode === 200) { 163 | return json_decode($response); 164 | } 165 | } catch (Exception $e) { 166 | // ignore 167 | } 168 | 169 | return null; 170 | } 171 | 172 | function searchCommitsForGitHubUsername(): string 173 | { 174 | $authorName = strtolower(trim(shell_exec('git config user.name'))); 175 | 176 | $committersRaw = shell_exec("git log --author='@users.noreply.github.com' --pretty='%an:%ae' --reverse"); 177 | $committersLines = explode("\n", $committersRaw ?? ''); 178 | $committers = array_filter(array_map(function ($line) use ($authorName) { 179 | $line = trim($line); 180 | [$name, $email] = explode(':', $line) + [null, null]; 181 | 182 | return [ 183 | 'name' => $name, 184 | 'email' => $email, 185 | 'isMatch' => strtolower($name) === $authorName && ! str_contains($name, '[bot]'), 186 | ]; 187 | }, $committersLines), fn ($item) => $item['isMatch']); 188 | 189 | if (empty($committers)) { 190 | return ''; 191 | } 192 | 193 | $firstCommitter = reset($committers); 194 | 195 | return explode('@', $firstCommitter['email'])[0] ?? ''; 196 | } 197 | 198 | function guessGitHubUsernameUsingCli() 199 | { 200 | try { 201 | if (preg_match('/ogged in to github\.com as ([a-zA-Z-_]+).+/', shell_exec('gh auth status -h github.com 2>&1'), $matches)) { 202 | return $matches[1]; 203 | } 204 | } catch (Exception $e) { 205 | // ignore 206 | } 207 | 208 | return ''; 209 | } 210 | 211 | function guessGitHubUsername(): string 212 | { 213 | $username = searchCommitsForGitHubUsername(); 214 | if (! empty($username)) { 215 | return $username; 216 | } 217 | 218 | $username = guessGitHubUsernameUsingCli(); 219 | if (! empty($username)) { 220 | return $username; 221 | } 222 | 223 | // fall back to using the username from the git remote 224 | $remoteUrl = shell_exec('git config remote.origin.url'); 225 | $remoteUrlParts = explode('/', str_replace(':', '/', trim($remoteUrl))); 226 | 227 | return $remoteUrlParts[1] ?? ''; 228 | } 229 | 230 | function guessGitHubVendorInfo($authorName, $username): array 231 | { 232 | $remoteUrl = shell_exec('git config remote.origin.url'); 233 | $remoteUrlParts = explode('/', str_replace(':', '/', trim($remoteUrl))); 234 | 235 | $response = getGitHubApiEndpoint("orgs/{$remoteUrlParts[1]}"); 236 | 237 | if ($response === null) { 238 | return [$authorName, $username]; 239 | } 240 | 241 | return [$response->name ?? $authorName, $response->login ?? $username]; 242 | } 243 | 244 | $gitName = run('git config user.name'); 245 | $authorName = ask('Author name', $gitName); 246 | 247 | $gitEmail = run('git config user.email'); 248 | $authorEmail = ask('Author email', $gitEmail); 249 | $authorUsername = ask('Author username', guessGitHubUsername()); 250 | 251 | $guessGitHubVendorInfo = guessGitHubVendorInfo($authorName, $authorUsername); 252 | 253 | $vendorName = ask('Vendor name', $guessGitHubVendorInfo[0]); 254 | $vendorUsername = ask('Vendor username', $guessGitHubVendorInfo[1] ?? slugify($vendorName)); 255 | $vendorSlug = slugify($vendorUsername); 256 | 257 | $vendorNamespace = str_replace('-', '', ucwords($vendorName)); 258 | $vendorNamespace = ask('Vendor namespace', $vendorNamespace); 259 | 260 | $currentDirectory = getcwd(); 261 | $folderName = basename($currentDirectory); 262 | 263 | $packageName = ask('Package name', $folderName); 264 | $packageSlug = slugify($packageName); 265 | $packageSlugWithoutPrefix = remove_prefix('laravel-', $packageSlug); 266 | 267 | $className = title_case($packageName); 268 | $className = ask('Class name', $className); 269 | $variableName = lcfirst($className); 270 | $description = ask('Package description', "This is my package {$packageSlug}"); 271 | 272 | $usePhpStan = confirm('Enable PhpStan?', true); 273 | $useLaravelPint = confirm('Enable Laravel Pint?', true); 274 | $useDependabot = confirm('Enable Dependabot?', true); 275 | $useLaravelRay = confirm('Use Ray for debugging?', true); 276 | $useUpdateChangelogWorkflow = confirm('Use automatic changelog updater workflow?', true); 277 | 278 | writeln('------'); 279 | writeln("Author : {$authorName} ({$authorUsername}, {$authorEmail})"); 280 | writeln("Vendor : {$vendorName} ({$vendorSlug})"); 281 | writeln("Package : {$packageSlug} <{$description}>"); 282 | writeln("Namespace : {$vendorNamespace}\\{$className}"); 283 | writeln("Class name : {$className}"); 284 | writeln('---'); 285 | writeln('Packages & Utilities'); 286 | writeln('Use Laravel/Pint : '.($useLaravelPint ? 'yes' : 'no')); 287 | writeln('Use Larastan/PhpStan : '.($usePhpStan ? 'yes' : 'no')); 288 | writeln('Use Dependabot : '.($useDependabot ? 'yes' : 'no')); 289 | writeln('Use Ray App : '.($useLaravelRay ? 'yes' : 'no')); 290 | writeln('Use Auto-Changelog : '.($useUpdateChangelogWorkflow ? 'yes' : 'no')); 291 | writeln('------'); 292 | 293 | writeln('This script will replace the above values in all relevant files in the project directory.'); 294 | 295 | if (! confirm('Modify files?', true)) { 296 | exit(1); 297 | } 298 | 299 | $files = (str_starts_with(strtoupper(PHP_OS), 'WIN') ? replaceForWindows() : replaceForAllOtherOSes()); 300 | 301 | foreach ($files as $file) { 302 | replace_in_file($file, [ 303 | ':author_name' => $authorName, 304 | ':author_username' => $authorUsername, 305 | 'author@domain.com' => $authorEmail, 306 | ':vendor_name' => $vendorName, 307 | ':vendor_slug' => $vendorSlug, 308 | 'VendorName' => $vendorNamespace, 309 | ':package_name' => $packageName, 310 | ':package_slug' => $packageSlug, 311 | ':package_slug_without_prefix' => $packageSlugWithoutPrefix, 312 | 'Skeleton' => $className, 313 | 'skeleton' => $packageSlug, 314 | 'migration_table_name' => title_snake($packageSlug), 315 | 'variable' => $variableName, 316 | ':package_description' => $description, 317 | ]); 318 | 319 | match (true) { 320 | str_contains($file, determineSeparator('src/Skeleton.php')) => rename($file, determineSeparator('./src/'.$className.'.php')), 321 | str_contains($file, determineSeparator('src/SkeletonServiceProvider.php')) => rename($file, determineSeparator('./src/'.$className.'ServiceProvider.php')), 322 | str_contains($file, determineSeparator('src/Facades/Skeleton.php')) => rename($file, determineSeparator('./src/Facades/'.$className.'.php')), 323 | str_contains($file, determineSeparator('src/Commands/SkeletonCommand.php')) => rename($file, determineSeparator('./src/Commands/'.$className.'Command.php')), 324 | str_contains($file, determineSeparator('database/migrations/create_skeleton_table.php.stub')) => rename($file, determineSeparator('./database/migrations/create_'.title_snake($packageSlugWithoutPrefix).'_table.php.stub')), 325 | str_contains($file, determineSeparator('config/skeleton.php')) => rename($file, determineSeparator('./config/'.$packageSlugWithoutPrefix.'.php')), 326 | str_contains($file, 'README.md') => remove_readme_paragraphs($file), 327 | default => [], 328 | }; 329 | } 330 | 331 | if (! $useLaravelPint) { 332 | safeUnlink(__DIR__.'/.github/workflows/fix-php-code-style-issues.yml'); 333 | safeUnlink(__DIR__.'/pint.json'); 334 | } 335 | 336 | if (! $usePhpStan) { 337 | safeUnlink(__DIR__.'/phpstan.neon.dist'); 338 | safeUnlink(__DIR__.'/phpstan-baseline.neon'); 339 | safeUnlink(__DIR__.'/.github/workflows/phpstan.yml'); 340 | 341 | remove_composer_deps([ 342 | 'phpstan/extension-installer', 343 | 'phpstan/phpstan-deprecation-rules', 344 | 'phpstan/phpstan-phpunit', 345 | 'larastan/larastan', 346 | ]); 347 | 348 | remove_composer_script('phpstan'); 349 | } 350 | 351 | if (! $useDependabot) { 352 | safeUnlink(__DIR__.'/.github/dependabot.yml'); 353 | safeUnlink(__DIR__.'/.github/workflows/dependabot-auto-merge.yml'); 354 | } 355 | 356 | if (! $useLaravelRay) { 357 | remove_composer_deps(['spatie/laravel-ray']); 358 | } 359 | 360 | if (! $useUpdateChangelogWorkflow) { 361 | safeUnlink(__DIR__.'/.github/workflows/update-changelog.yml'); 362 | } 363 | 364 | confirm('Execute `composer install` and run tests?') && run('composer install && composer test'); 365 | 366 | confirm('Let this script delete itself?', true) && unlink(__FILE__); 367 | -------------------------------------------------------------------------------- /database/factories/MailLogFactory.php: -------------------------------------------------------------------------------- 1 | faker->numberBetween(0, 5); $i++) { 18 | $attachments[] = [ 19 | 'name' => $this->faker->word.'.'.$this->faker->fileExtension(), 20 | 'mime' => $this->faker->randomElement(['application/pdf', 'image/jpeg', 'image/png']), 21 | 'size' => $this->faker->numberBetween(1000, 10000), 22 | ]; 23 | } 24 | 25 | $to_email = $this->faker->email; 26 | $to_email_domain = Str::after($to_email, '@'); 27 | 28 | return [ 29 | 'message_id' => $this->faker->uuid, 30 | 'sent_at' => $this->faker->dateTimeBetween('-1 year', 'now'), 31 | 'from_email' => $this->faker->email, 32 | 'from_name' => $this->faker->name, 33 | 'to_email' => $to_email, 34 | 'to_email_domain' => $to_email_domain, 35 | 'to_name' => $this->faker->name, 36 | 'subject' => $this->faker->sentence, 37 | 'content_html' => $this->faker->paragraph, 38 | 'content_text' => $this->faker->paragraph, 39 | 'headers' => $this->faker->randomElement([null, $this->faker->word]), 40 | 'mailer' => $this->faker->randomElement([null, $this->faker->word]), 41 | 'status' => $this->faker->randomElement(['success', 'failed']), 42 | 'error_message' => $this->faker->randomElement([null, $this->faker->sentence]), 43 | 'attachments' => $attachments, 44 | ]; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /database/factories/ModelFactory.php: -------------------------------------------------------------------------------- 1 | id(); 14 | $table->timestamps(); 15 | 16 | $table->string('message_id')->unique()->index(); 17 | $table->timestamp('sent_at'); // desc index below 18 | $table->string('from_email'); 19 | $table->string('from_name')->nullable(); 20 | $table->string('to_email')->index(); 21 | $table->string('to_email_domain')->index(); 22 | $table->string('to_name')->index()->nullable(); 23 | $table->string('subject')->index(); 24 | $table->text('content_html')->nullable(); 25 | $table->text('content_text')->nullable(); 26 | $table->text('headers')->nullable(); 27 | 28 | $table->string('mailer')->nullable(); 29 | $table->string('status'); // success, failed, etc 30 | $table->text('error_message')->nullable(); 31 | 32 | $table->json('attachments')->nullable()->comment('Array of attachments, each with filename, mime type, and size'); 33 | }); 34 | 35 | // create a descending index on sent_at so we can quickly display the newest email first 36 | DB::statement('CREATE INDEX mail_logs_sent_at_index_desc ON mail_logs (sent_at desc)'); 37 | 38 | } 39 | 40 | public function down() 41 | { 42 | Schema::dropIfExists('mail_logs'); 43 | } 44 | }; 45 | -------------------------------------------------------------------------------- /database/seeders/MailLogSeeder.php: -------------------------------------------------------------------------------- 1 | count(50) 17 | ->create(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /dist/build/assets/MailShow-BdT1JXFW.js: -------------------------------------------------------------------------------- 1 | import{s as u,d as m,a as f}from"./dayjs.min-NtYHfqg0.js";import{B as p,c as r,o as s,D as h,F as i,C as b,m as c,U as v,a as e,N as t,am as y,L as d,R as k,ap as l}from"./app-aQLUJyJ9.js";var w=function(o){var a=o.dt;return` 2 | .p-tag { 3 | display: inline-flex; 4 | align-items: center; 5 | justify-content: center; 6 | background: `.concat(a("tag.primary.background"),`; 7 | color: `).concat(a("tag.primary.color"),`; 8 | font-size: `).concat(a("tag.font.size"),`; 9 | font-weight: `).concat(a("tag.font.weight"),`; 10 | padding: `).concat(a("tag.padding"),`; 11 | border-radius: `).concat(a("tag.border.radius"),`; 12 | gap: `).concat(a("tag.gap"),`; 13 | } 14 | 15 | .p-tag-icon { 16 | font-size: `).concat(a("tag.icon.size"),`; 17 | width: `).concat(a("tag.icon.size"),`; 18 | height:`).concat(a("tag.icon.size"),`; 19 | } 20 | 21 | .p-tag-rounded { 22 | border-radius: `).concat(a("tag.rounded.border.radius"),`; 23 | } 24 | 25 | .p-tag-success { 26 | background: `).concat(a("tag.success.background"),`; 27 | color: `).concat(a("tag.success.color"),`; 28 | } 29 | 30 | .p-tag-info { 31 | background: `).concat(a("tag.info.background"),`; 32 | color: `).concat(a("tag.info.color"),`; 33 | } 34 | 35 | .p-tag-warn { 36 | background: `).concat(a("tag.warn.background"),`; 37 | color: `).concat(a("tag.warn.color"),`; 38 | } 39 | 40 | .p-tag-danger { 41 | background: `).concat(a("tag.danger.background"),`; 42 | color: `).concat(a("tag.danger.color"),`; 43 | } 44 | 45 | .p-tag-secondary { 46 | background: `).concat(a("tag.secondary.background"),`; 47 | color: `).concat(a("tag.secondary.color"),`; 48 | } 49 | 50 | .p-tag-contrast { 51 | background: `).concat(a("tag.contrast.background"),`; 52 | color: `).concat(a("tag.contrast.color"),`; 53 | } 54 | `)},$={root:function(o){var a=o.props;return["p-tag p-component",{"p-tag-info":a.severity==="info","p-tag-success":a.severity==="success","p-tag-warn":a.severity==="warn","p-tag-danger":a.severity==="danger","p-tag-secondary":a.severity==="secondary","p-tag-contrast":a.severity==="contrast","p-tag-rounded":a.rounded}]},icon:"p-tag-icon",label:"p-tag-label"},x=p.extend({name:"tag",theme:w,classes:$}),B={name:"BaseTag",extends:u,props:{value:null,severity:null,rounded:Boolean,icon:String},style:x,provide:function(){return{$pcTag:this,$parentInstance:this}}},g={name:"Tag",extends:B,inheritAttrs:!1};function j(n,o,a,I,L,O){return s(),r("span",c({class:n.cx("root")},n.ptmi("root")),[n.$slots.icon?(s(),h(v(n.$slots.icon),c({key:0,class:n.cx("icon")},n.ptm("icon")),null,16,["class"])):n.icon?(s(),r("span",c({key:1,class:[n.cx("icon"),n.icon]},n.ptm("icon")),null,16)):i("",!0),n.value!=null||n.$slots.default?b(n.$slots,"default",{key:2},function(){return[e("span",c({class:n.cx("label")},n.ptm("label")),t(n.value),17)]}):i("",!0)],16)}g.render=j;const z={class:"h-full p-2"},S={class:"flex w-full flex-col space-y-4"},C={class:"flex-none"},M={class:"flex items-baseline justify-between"},T={class:"mb-4 text-2xl font-bold"},_={class:"text-muted-color text-sm"},D={class:"flex items-center justify-between"},N={class:""},Y={class:""},V={class:"text-muted-color text-sm"},A={key:0,class:"flex-none rounded border border-red-200 bg-red-50 p-4"},F={class:"text-red-800"},q={class:"mt-4 flex grow items-stretch overflow-clip rounded-lg"},E=["srcdoc"],U=y({__name:"MailShow",props:{mail:{type:Object,required:!0}},setup(n){return(o,a)=>(s(),r("div",z,[d(l(f),{class:"min-h-full",pt:{body:{class:"grow"},content:{class:"grow flex items-stretch"}}},{content:k(()=>[e("div",S,[e("div",C,[e("div",M,[e("h1",T,t(n.mail.subject),1),e("div",_,t(l(m)(n.mail.sent_at).format("MMMM D, YYYY h:mm A")),1)]),e("div",D,[e("div",N,[e("p",Y," To: "+t(n.mail.to_name?`${n.mail.to_name} <${n.mail.to_email}>`:n.mail.to_email),1),e("p",V," From: "+t(n.mail.from_name?`${n.mail.from_name} <${n.mail.from_email}>`:n.mail.from_email),1)]),d(l(g),{severity:n.mail.status==="success"?"success":"danger",value:n.mail.status,rounded:""},null,8,["severity","value"])])]),n.mail.error_message?(s(),r("div",A,[e("p",F,t(n.mail.error_message),1)])):i("",!0),e("div",q,[e("iframe",{class:"w-full",srcdoc:n.mail.content_html,frameborder:"0",allowfullscreen:""},null,8,E)])])]),_:1})]))}});export{U as default}; 55 | -------------------------------------------------------------------------------- /dist/build/assets/app-gflgPwOp.css: -------------------------------------------------------------------------------- 1 | /*! tailwindcss v4.0.6 | MIT License | https://tailwindcss.com */@layer theme{:root,:host{--font-sans:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--font-serif:ui-serif,Georgia,Cambria,"Times New Roman",Times,serif;--font-mono:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--color-red-50:oklch(.971 .013 17.38);--color-red-100:oklch(.936 .032 17.717);--color-red-200:oklch(.885 .062 18.334);--color-red-300:oklch(.808 .114 19.571);--color-red-400:oklch(.704 .191 22.216);--color-red-500:oklch(.637 .237 25.331);--color-red-600:oklch(.577 .245 27.325);--color-red-700:oklch(.505 .213 27.518);--color-red-800:oklch(.444 .177 26.899);--color-red-900:oklch(.396 .141 25.723);--color-red-950:oklch(.258 .092 26.042);--color-orange-50:oklch(.98 .016 73.684);--color-orange-100:oklch(.954 .038 75.164);--color-orange-200:oklch(.901 .076 70.697);--color-orange-300:oklch(.837 .128 66.29);--color-orange-400:oklch(.75 .183 55.934);--color-orange-500:oklch(.705 .213 47.604);--color-orange-600:oklch(.646 .222 41.116);--color-orange-700:oklch(.553 .195 38.402);--color-orange-800:oklch(.47 .157 37.304);--color-orange-900:oklch(.408 .123 38.172);--color-orange-950:oklch(.266 .079 36.259);--color-amber-50:oklch(.987 .022 95.277);--color-amber-100:oklch(.962 .059 95.617);--color-amber-200:oklch(.924 .12 95.746);--color-amber-300:oklch(.879 .169 91.605);--color-amber-400:oklch(.828 .189 84.429);--color-amber-500:oklch(.769 .188 70.08);--color-amber-600:oklch(.666 .179 58.318);--color-amber-700:oklch(.555 .163 48.998);--color-amber-800:oklch(.473 .137 46.201);--color-amber-900:oklch(.414 .112 45.904);--color-amber-950:oklch(.279 .077 45.635);--color-yellow-50:oklch(.987 .026 102.212);--color-yellow-100:oklch(.973 .071 103.193);--color-yellow-200:oklch(.945 .129 101.54);--color-yellow-300:oklch(.905 .182 98.111);--color-yellow-400:oklch(.852 .199 91.936);--color-yellow-500:oklch(.795 .184 86.047);--color-yellow-600:oklch(.681 .162 75.834);--color-yellow-700:oklch(.554 .135 66.442);--color-yellow-800:oklch(.476 .114 61.907);--color-yellow-900:oklch(.421 .095 57.708);--color-yellow-950:oklch(.286 .066 53.813);--color-lime-50:oklch(.986 .031 120.757);--color-lime-100:oklch(.967 .067 122.328);--color-lime-200:oklch(.938 .127 124.321);--color-lime-300:oklch(.897 .196 126.665);--color-lime-400:oklch(.841 .238 128.85);--color-lime-500:oklch(.768 .233 130.85);--color-lime-600:oklch(.648 .2 131.684);--color-lime-700:oklch(.532 .157 131.589);--color-lime-800:oklch(.453 .124 130.933);--color-lime-900:oklch(.405 .101 131.063);--color-lime-950:oklch(.274 .072 132.109);--color-green-50:oklch(.982 .018 155.826);--color-green-100:oklch(.962 .044 156.743);--color-green-200:oklch(.925 .084 155.995);--color-green-300:oklch(.871 .15 154.449);--color-green-400:oklch(.792 .209 151.711);--color-green-500:oklch(.723 .219 149.579);--color-green-600:oklch(.627 .194 149.214);--color-green-700:oklch(.527 .154 150.069);--color-green-800:oklch(.448 .119 151.328);--color-green-900:oklch(.393 .095 152.535);--color-green-950:oklch(.266 .065 152.934);--color-emerald-50:oklch(.979 .021 166.113);--color-emerald-100:oklch(.95 .052 163.051);--color-emerald-200:oklch(.905 .093 164.15);--color-emerald-300:oklch(.845 .143 164.978);--color-emerald-400:oklch(.765 .177 163.223);--color-emerald-500:oklch(.696 .17 162.48);--color-emerald-600:oklch(.596 .145 163.225);--color-emerald-700:oklch(.508 .118 165.612);--color-emerald-800:oklch(.432 .095 166.913);--color-emerald-900:oklch(.378 .077 168.94);--color-emerald-950:oklch(.262 .051 172.552);--color-teal-50:oklch(.984 .014 180.72);--color-teal-100:oklch(.953 .051 180.801);--color-teal-200:oklch(.91 .096 180.426);--color-teal-300:oklch(.855 .138 181.071);--color-teal-400:oklch(.777 .152 181.912);--color-teal-500:oklch(.704 .14 182.503);--color-teal-600:oklch(.6 .118 184.704);--color-teal-700:oklch(.511 .096 186.391);--color-teal-800:oklch(.437 .078 188.216);--color-teal-900:oklch(.386 .063 188.416);--color-teal-950:oklch(.277 .046 192.524);--color-cyan-50:oklch(.984 .019 200.873);--color-cyan-100:oklch(.956 .045 203.388);--color-cyan-200:oklch(.917 .08 205.041);--color-cyan-300:oklch(.865 .127 207.078);--color-cyan-400:oklch(.789 .154 211.53);--color-cyan-500:oklch(.715 .143 215.221);--color-cyan-600:oklch(.609 .126 221.723);--color-cyan-700:oklch(.52 .105 223.128);--color-cyan-800:oklch(.45 .085 224.283);--color-cyan-900:oklch(.398 .07 227.392);--color-cyan-950:oklch(.302 .056 229.695);--color-sky-50:oklch(.977 .013 236.62);--color-sky-100:oklch(.951 .026 236.824);--color-sky-200:oklch(.901 .058 230.902);--color-sky-300:oklch(.828 .111 230.318);--color-sky-400:oklch(.746 .16 232.661);--color-sky-500:oklch(.685 .169 237.323);--color-sky-600:oklch(.588 .158 241.966);--color-sky-700:oklch(.5 .134 242.749);--color-sky-800:oklch(.443 .11 240.79);--color-sky-900:oklch(.391 .09 240.876);--color-sky-950:oklch(.293 .066 243.157);--color-blue-50:oklch(.97 .014 254.604);--color-blue-100:oklch(.932 .032 255.585);--color-blue-200:oklch(.882 .059 254.128);--color-blue-300:oklch(.809 .105 251.813);--color-blue-400:oklch(.707 .165 254.624);--color-blue-500:oklch(.623 .214 259.815);--color-blue-600:oklch(.546 .245 262.881);--color-blue-700:oklch(.488 .243 264.376);--color-blue-800:oklch(.424 .199 265.638);--color-blue-900:oklch(.379 .146 265.522);--color-blue-950:oklch(.282 .091 267.935);--color-indigo-50:oklch(.962 .018 272.314);--color-indigo-100:oklch(.93 .034 272.788);--color-indigo-200:oklch(.87 .065 274.039);--color-indigo-300:oklch(.785 .115 274.713);--color-indigo-400:oklch(.673 .182 276.935);--color-indigo-500:oklch(.585 .233 277.117);--color-indigo-600:oklch(.511 .262 276.966);--color-indigo-700:oklch(.457 .24 277.023);--color-indigo-800:oklch(.398 .195 277.366);--color-indigo-900:oklch(.359 .144 278.697);--color-indigo-950:oklch(.257 .09 281.288);--color-violet-50:oklch(.969 .016 293.756);--color-violet-100:oklch(.943 .029 294.588);--color-violet-200:oklch(.894 .057 293.283);--color-violet-300:oklch(.811 .111 293.571);--color-violet-400:oklch(.702 .183 293.541);--color-violet-500:oklch(.606 .25 292.717);--color-violet-600:oklch(.541 .281 293.009);--color-violet-700:oklch(.491 .27 292.581);--color-violet-800:oklch(.432 .232 292.759);--color-violet-900:oklch(.38 .189 293.745);--color-violet-950:oklch(.283 .141 291.089);--color-purple-50:oklch(.977 .014 308.299);--color-purple-100:oklch(.946 .033 307.174);--color-purple-200:oklch(.902 .063 306.703);--color-purple-300:oklch(.827 .119 306.383);--color-purple-400:oklch(.714 .203 305.504);--color-purple-500:oklch(.627 .265 303.9);--color-purple-600:oklch(.558 .288 302.321);--color-purple-700:oklch(.496 .265 301.924);--color-purple-800:oklch(.438 .218 303.724);--color-purple-900:oklch(.381 .176 304.987);--color-purple-950:oklch(.291 .149 302.717);--color-fuchsia-50:oklch(.977 .017 320.058);--color-fuchsia-100:oklch(.952 .037 318.852);--color-fuchsia-200:oklch(.903 .076 319.62);--color-fuchsia-300:oklch(.833 .145 321.434);--color-fuchsia-400:oklch(.74 .238 322.16);--color-fuchsia-500:oklch(.667 .295 322.15);--color-fuchsia-600:oklch(.591 .293 322.896);--color-fuchsia-700:oklch(.518 .253 323.949);--color-fuchsia-800:oklch(.452 .211 324.591);--color-fuchsia-900:oklch(.401 .17 325.612);--color-fuchsia-950:oklch(.293 .136 325.661);--color-pink-50:oklch(.971 .014 343.198);--color-pink-100:oklch(.948 .028 342.258);--color-pink-200:oklch(.899 .061 343.231);--color-pink-300:oklch(.823 .12 346.018);--color-pink-400:oklch(.718 .202 349.761);--color-pink-500:oklch(.656 .241 354.308);--color-pink-600:oklch(.592 .249 .584);--color-pink-700:oklch(.525 .223 3.958);--color-pink-800:oklch(.459 .187 3.815);--color-pink-900:oklch(.408 .153 2.432);--color-pink-950:oklch(.284 .109 3.907);--color-rose-50:oklch(.969 .015 12.422);--color-rose-100:oklch(.941 .03 12.58);--color-rose-200:oklch(.892 .058 10.001);--color-rose-300:oklch(.81 .117 11.638);--color-rose-400:oklch(.712 .194 13.428);--color-rose-500:oklch(.645 .246 16.439);--color-rose-600:oklch(.586 .253 17.585);--color-rose-700:oklch(.514 .222 16.935);--color-rose-800:oklch(.455 .188 13.697);--color-rose-900:oklch(.41 .159 10.272);--color-rose-950:oklch(.271 .105 12.094);--color-slate-50:oklch(.984 .003 247.858);--color-slate-100:oklch(.968 .007 247.896);--color-slate-200:oklch(.929 .013 255.508);--color-slate-300:oklch(.869 .022 252.894);--color-slate-400:oklch(.704 .04 256.788);--color-slate-500:oklch(.554 .046 257.417);--color-slate-600:oklch(.446 .043 257.281);--color-slate-700:oklch(.372 .044 257.287);--color-slate-800:oklch(.279 .041 260.031);--color-slate-900:oklch(.208 .042 265.755);--color-slate-950:oklch(.129 .042 264.695);--color-gray-50:oklch(.985 .002 247.839);--color-gray-100:oklch(.967 .003 264.542);--color-gray-200:oklch(.928 .006 264.531);--color-gray-300:oklch(.872 .01 258.338);--color-gray-400:oklch(.707 .022 261.325);--color-gray-500:oklch(.551 .027 264.364);--color-gray-600:oklch(.446 .03 256.802);--color-gray-700:oklch(.373 .034 259.733);--color-gray-800:oklch(.278 .033 256.848);--color-gray-900:oklch(.21 .034 264.665);--color-gray-950:oklch(.13 .028 261.692);--color-zinc-50:oklch(.985 0 0);--color-zinc-100:oklch(.967 .001 286.375);--color-zinc-200:oklch(.92 .004 286.32);--color-zinc-300:oklch(.871 .006 286.286);--color-zinc-400:oklch(.705 .015 286.067);--color-zinc-500:oklch(.552 .016 285.938);--color-zinc-600:oklch(.442 .017 285.786);--color-zinc-700:oklch(.37 .013 285.805);--color-zinc-800:oklch(.274 .006 286.033);--color-zinc-900:oklch(.21 .006 285.885);--color-zinc-950:oklch(.141 .005 285.823);--color-neutral-50:oklch(.985 0 0);--color-neutral-100:oklch(.97 0 0);--color-neutral-200:oklch(.922 0 0);--color-neutral-300:oklch(.87 0 0);--color-neutral-400:oklch(.708 0 0);--color-neutral-500:oklch(.556 0 0);--color-neutral-600:oklch(.439 0 0);--color-neutral-700:oklch(.371 0 0);--color-neutral-800:oklch(.269 0 0);--color-neutral-900:oklch(.205 0 0);--color-neutral-950:oklch(.145 0 0);--color-stone-50:oklch(.985 .001 106.423);--color-stone-100:oklch(.97 .001 106.424);--color-stone-200:oklch(.923 .003 48.717);--color-stone-300:oklch(.869 .005 56.366);--color-stone-400:oklch(.709 .01 56.259);--color-stone-500:oklch(.553 .013 58.071);--color-stone-600:oklch(.444 .011 73.639);--color-stone-700:oklch(.374 .01 67.558);--color-stone-800:oklch(.268 .007 34.298);--color-stone-900:oklch(.216 .006 56.043);--color-stone-950:oklch(.147 .004 49.25);--color-black:#000;--color-white:#fff;--spacing:.25rem;--breakpoint-sm:40rem;--breakpoint-md:48rem;--breakpoint-lg:64rem;--breakpoint-xl:80rem;--breakpoint-2xl:96rem;--container-3xs:16rem;--container-2xs:18rem;--container-xs:20rem;--container-sm:24rem;--container-md:28rem;--container-lg:32rem;--container-xl:36rem;--container-2xl:42rem;--container-3xl:48rem;--container-4xl:56rem;--container-5xl:64rem;--container-6xl:72rem;--container-7xl:80rem;--text-xs:.75rem;--text-xs--line-height:calc(1/.75);--text-sm:.875rem;--text-sm--line-height:calc(1.25/.875);--text-base:1rem;--text-base--line-height: 1.5 ;--text-lg:1.125rem;--text-lg--line-height:calc(1.75/1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75/1.25);--text-2xl:1.5rem;--text-2xl--line-height:calc(2/1.5);--text-3xl:1.875rem;--text-3xl--line-height: 1.2 ;--text-4xl:2.25rem;--text-4xl--line-height:calc(2.5/2.25);--text-5xl:3rem;--text-5xl--line-height:1;--text-6xl:3.75rem;--text-6xl--line-height:1;--text-7xl:4.5rem;--text-7xl--line-height:1;--text-8xl:6rem;--text-8xl--line-height:1;--text-9xl:8rem;--text-9xl--line-height:1;--font-weight-thin:100;--font-weight-extralight:200;--font-weight-light:300;--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--font-weight-extrabold:800;--font-weight-black:900;--tracking-tighter:-.05em;--tracking-tight:-.025em;--tracking-normal:0em;--tracking-wide:.025em;--tracking-wider:.05em;--tracking-widest:.1em;--leading-tight:1.25;--leading-snug:1.375;--leading-normal:1.5;--leading-relaxed:1.625;--leading-loose:2;--radius-xs:.125rem;--radius-sm:.25rem;--radius-md:.375rem;--radius-lg:.5rem;--radius-xl:.75rem;--radius-2xl:1rem;--radius-3xl:1.5rem;--radius-4xl:2rem;--shadow-2xs:0 1px #0000000d;--shadow-xs:0 1px 2px 0 #0000000d;--shadow-sm:0 1px 3px 0 #0000001a,0 1px 2px -1px #0000001a;--shadow-md:0 4px 6px -1px #0000001a,0 2px 4px -2px #0000001a;--shadow-lg:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a;--shadow-xl:0 20px 25px -5px #0000001a,0 8px 10px -6px #0000001a;--shadow-2xl:0 25px 50px -12px #00000040;--inset-shadow-2xs:inset 0 1px #0000000d;--inset-shadow-xs:inset 0 1px 1px #0000000d;--inset-shadow-sm:inset 0 2px 4px #0000000d;--drop-shadow-xs:0 1px 1px #0000000d;--drop-shadow-sm:0 1px 2px #00000026;--drop-shadow-md:0 3px 3px #0000001f;--drop-shadow-lg:0 4px 4px #00000026;--drop-shadow-xl:0 9px 7px #0000001a;--drop-shadow-2xl:0 25px 25px #00000026;--ease-in:cubic-bezier(.4,0,1,1);--ease-out:cubic-bezier(0,0,.2,1);--ease-in-out:cubic-bezier(.4,0,.2,1);--animate-spin:spin 1s linear infinite;--animate-ping:ping 1s cubic-bezier(0,0,.2,1)infinite;--animate-pulse:pulse 2s cubic-bezier(.4,0,.6,1)infinite;--animate-bounce:bounce 1s infinite;--blur-xs:4px;--blur-sm:8px;--blur-md:12px;--blur-lg:16px;--blur-xl:24px;--blur-2xl:40px;--blur-3xl:64px;--perspective-dramatic:100px;--perspective-near:300px;--perspective-normal:500px;--perspective-midrange:800px;--perspective-distant:1200px;--aspect-video:16/9;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4,0,.2,1);--default-font-family:var(--font-sans);--default-font-feature-settings:var(--font-sans--font-feature-settings);--default-font-variation-settings:var(--font-sans--font-variation-settings);--default-mono-font-family:var(--font-mono);--default-mono-font-feature-settings:var(--font-mono--font-feature-settings);--default-mono-font-variation-settings:var(--font-mono--font-variation-settings)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;-moz-tab-size:4;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}body{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;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1;color:color-mix(in oklab,currentColor 50%,transparent)}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){-webkit-appearance:button;-moz-appearance:button;appearance:button}::file-selector-button{-webkit-appearance:button;-moz-appearance:button;appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.collapse{visibility:collapse}.visible{visibility:visible}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.sticky{position:sticky}.top-0{top:calc(var(--spacing)*0)}.-bottom-16{bottom:calc(var(--spacing)*-16)}.-left-16{left:calc(var(--spacing)*-16)}.-left-20{left:calc(var(--spacing)*-20)}.z-0{z-index:0}.\!row-span-1{grid-row:span 1/span 1!important}.\!container{width:100%!important}@media (width>=40rem){.\!container{max-width:40rem!important}}@media (width>=48rem){.\!container{max-width:48rem!important}}@media (width>=64rem){.\!container{max-width:64rem!important}}@media (width>=80rem){.\!container{max-width:80rem!important}}@media (width>=96rem){.\!container{max-width:96rem!important}}.container{width:100%}@media (width>=40rem){.container{max-width:40rem}}@media (width>=48rem){.container{max-width:48rem}}@media (width>=64rem){.container{max-width:64rem}}@media (width>=80rem){.container{max-width:80rem}}@media (width>=96rem){.container{max-width:96rem}}.-mx-3{margin-inline:calc(var(--spacing)*-3)}.mt-4{margin-top:calc(var(--spacing)*4)}.mt-6{margin-top:calc(var(--spacing)*6)}.mb-4{margin-bottom:calc(var(--spacing)*4)}.-ml-px{margin-left:-1px}.ml-3{margin-left:calc(var(--spacing)*3)}.\!hidden{display:none!important}.block{display:block}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.table{display:table}.aspect-video{aspect-ratio:var(--aspect-video)}.size-3{width:calc(var(--spacing)*3);height:calc(var(--spacing)*3)}.size-5{width:calc(var(--spacing)*5);height:calc(var(--spacing)*5)}.size-6{width:calc(var(--spacing)*6);height:calc(var(--spacing)*6)}.size-12{width:calc(var(--spacing)*12);height:calc(var(--spacing)*12)}.h-5{height:calc(var(--spacing)*5)}.h-12{height:calc(var(--spacing)*12)}.h-40{height:calc(var(--spacing)*40)}.h-full{height:100%}.min-h-dvh{min-height:100dvh}.min-h-full{min-height:100%}.min-h-screen{min-height:100vh}.w-4{width:calc(var(--spacing)*4)}.w-5{width:calc(var(--spacing)*5)}.w-60{width:calc(var(--spacing)*60)}.w-64{width:calc(var(--spacing)*64)}.w-\[calc\(100\%_\+_8rem\)\]{width:calc(100% + 8rem)}.w-auto{width:auto}.w-full{width:100%}.max-w-2xl{max-width:var(--container-2xl)}.max-w-\[877px\]{max-width:877px}.max-w-full{max-width:100%}.min-w-0{min-width:calc(var(--spacing)*0)}.min-w-24{min-width:calc(var(--spacing)*24)}.flex-1{flex:1}.flex-none{flex:none}.flex-shrink{flex-shrink:1}.shrink-0{flex-shrink:0}.flex-grow,.grow{flex-grow:1}.basis-0{flex-basis:calc(var(--spacing)*0)}.border-collapse{border-collapse:collapse}.transform{transform:var(--tw-rotate-x)var(--tw-rotate-y)var(--tw-rotate-z)var(--tw-skew-x)var(--tw-skew-y)}.cursor-default{cursor:default}.cursor-pointer{cursor:pointer}.resize{resize:both}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.\!flex-row{flex-direction:row!important}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-baseline{align-items:baseline}.items-center{align-items:center}.items-start{align-items:flex-start}.items-stretch{align-items:stretch}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.justify-start{justify-content:flex-start}.justify-items-center{justify-items:center}.gap-2{gap:calc(var(--spacing)*2)}.gap-4{gap:calc(var(--spacing)*4)}.gap-6{gap:calc(var(--spacing)*6)}.gap-x-1{column-gap:calc(var(--spacing)*1)}.gap-x-4{column-gap:calc(var(--spacing)*4)}:where(.space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*4)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*4)*calc(1 - var(--tw-space-y-reverse)))}.self-center{align-self:center}.overflow-clip{overflow:clip}.overflow-hidden{overflow:hidden}.rounded{border-radius:.25rem}.rounded-\[10px\]{border-radius:10px}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-sm{border-radius:var(--radius-sm)}.rounded-l-md{border-top-left-radius:var(--radius-md);border-bottom-left-radius:var(--radius-md)}.rounded-r-md{border-top-right-radius:var(--radius-md);border-bottom-right-radius:var(--radius-md)}.border{border-style:var(--tw-border-style);border-width:1px}.border-gray-300{border-color:var(--color-gray-300)}.border-red-200{border-color:var(--color-red-200)}.bg-\[\#FF2D20\]\/10{background-color:#ff2d201a}.bg-gray-50{background-color:var(--color-gray-50)}.bg-red-50{background-color:var(--color-red-50)}.bg-surface-300{background-color:color-mix(in srgb,var(--p-surface-300) 100%,transparent)}.bg-white{background-color:var(--color-white)}.bg-gradient-to-b{--tw-gradient-position:to bottom in oklab;background-image:linear-gradient(var(--tw-gradient-stops))}.from-transparent{--tw-gradient-from:transparent;--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.via-white{--tw-gradient-via:var(--color-white);--tw-gradient-via-stops:var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-via)var(--tw-gradient-via-position),var(--tw-gradient-to)var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-via-stops)}.to-white{--tw-gradient-to:var(--color-white);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.to-zinc-900{--tw-gradient-to:var(--color-zinc-900);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.fill-gray-400{fill:var(--color-gray-400)}.stroke-\[\#FF2D20\]{stroke:#ff2d20}.object-cover{object-fit:cover}.object-top{object-position:top}.p-2{padding:calc(var(--spacing)*2)}.p-4{padding:calc(var(--spacing)*4)}.p-6{padding:calc(var(--spacing)*6)}.px-2{padding-inline:calc(var(--spacing)*2)}.px-3{padding-inline:calc(var(--spacing)*3)}.px-4{padding-inline:calc(var(--spacing)*4)}.px-6{padding-inline:calc(var(--spacing)*6)}.px-8{padding-inline:calc(var(--spacing)*8)}.py-2{padding-block:calc(var(--spacing)*2)}.py-10{padding-block:calc(var(--spacing)*10)}.py-16{padding-block:calc(var(--spacing)*16)}.pt-3{padding-top:calc(var(--spacing)*3)}.pt-6{padding-top:calc(var(--spacing)*6)}.pr-2{padding-right:calc(var(--spacing)*2)}.pl-2{padding-left:calc(var(--spacing)*2)}.pl-4{padding-left:calc(var(--spacing)*4)}.text-center{text-align:center}.font-sans{font-family:var(--font-sans)}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-sm\/relaxed{font-size:var(--text-sm);line-height:var(--leading-relaxed)}.leading-5{--tw-leading:calc(var(--spacing)*5);line-height:calc(var(--spacing)*5)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.text-ellipsis{text-overflow:ellipsis}.whitespace-nowrap{white-space:nowrap}.text-black{color:var(--color-black)}.text-black\/50{color:color-mix(in oklab,var(--color-black)50%,transparent)}.text-gray-500{color:var(--color-gray-500)}.text-gray-700{color:var(--color-gray-700)}.text-muted-color{color:var(--p-text-muted-color)}.text-red-800{color:var(--color-red-800)}.text-white{color:var(--color-white)}.capitalize{text-transform:capitalize}.lowercase{text-transform:lowercase}.uppercase{text-transform:uppercase}.underline{text-decoration-line:underline}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.ring,.ring-1{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(1px + var(--tw-ring-offset-width))var(--tw-ring-color,currentColor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a),0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-\[0px_14px_34px_0px_rgba\(0\,0\,0\,0\.08\)\]{--tw-shadow:0px 14px 34px 0px var(--tw-shadow-color,#00000014);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a),0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.ring-black{--tw-ring-color:var(--color-black)}.ring-gray-300{--tw-ring-color:var(--color-gray-300)}.ring-transparent{--tw-ring-color:transparent}.ring-white{--tw-ring-color:var(--color-white)}.ring-white\/\[0\.05\]{--tw-ring-color:color-mix(in oklab,var(--color-white)5%,transparent)}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.blur{--tw-blur:blur(8px);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,)}.drop-shadow{--tw-drop-shadow:drop-shadow(0 1px 2px #0000001a)drop-shadow(0 1px 1px #0000000f);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,)}.drop-shadow-\[0px_4px_34px_rgba\(0\,0\,0\,0\.06\)\]{--tw-drop-shadow:drop-shadow(0px 4px 34px #0000000f);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,)}.drop-shadow-\[0px_4px_34px_rgba\(0\,0\,0\,0\.25\)\]{--tw-drop-shadow:drop-shadow(0px 4px 34px #00000040);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,)}.\!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,)!important}.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,)}.backdrop-filter{-webkit-backdrop-filter:var(--tw-backdrop-blur,)var(--tw-backdrop-brightness,)var(--tw-backdrop-contrast,)var(--tw-backdrop-grayscale,)var(--tw-backdrop-hue-rotate,)var(--tw-backdrop-invert,)var(--tw-backdrop-opacity,)var(--tw-backdrop-saturate,)var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,)var(--tw-backdrop-brightness,)var(--tw-backdrop-contrast,)var(--tw-backdrop-grayscale,)var(--tw-backdrop-hue-rotate,)var(--tw-backdrop-invert,)var(--tw-backdrop-opacity,)var(--tw-backdrop-saturate,)var(--tw-backdrop-sepia,)}.\!transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter!important;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function))!important;transition-duration:var(--tw-duration,var(--default-transition-duration))!important}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,-webkit-backdrop-filter,backdrop-filter;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-150{--tw-duration:.15s;transition-duration:.15s}.duration-300{--tw-duration:.3s;transition-duration:.3s}.ease-in{--tw-ease:var(--ease-in);transition-timing-function:var(--ease-in)}.ease-in-out{--tw-ease:var(--ease-in-out);transition-timing-function:var(--ease-in-out)}.ease-out{--tw-ease:var(--ease-out);transition-timing-function:var(--ease-out)}.selection\:bg-\[\#FF2D20\] ::selection{background-color:#ff2d20}.selection\:bg-\[\#FF2D20\]::selection{background-color:#ff2d20}.selection\:text-white ::selection{color:var(--color-white)}.selection\:text-white::selection{color:var(--color-white)}@media (hover:hover){.hover\:bg-surface-100:hover{background-color:color-mix(in srgb,var(--p-surface-100) 100%,transparent)}.hover\:text-black:hover{color:var(--color-black)}.hover\:text-black\/70:hover{color:color-mix(in oklab,var(--color-black)70%,transparent)}.hover\:ring-black\/20:hover{--tw-ring-color:color-mix(in oklab,var(--color-black)20%,transparent)}}.focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}.focus-visible\:ring-1:focus-visible{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(1px + var(--tw-ring-offset-width))var(--tw-ring-color,currentColor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus-visible\:ring-\[\#FF2D20\]:focus-visible{--tw-ring-color:#ff2d20}@media (width>=40rem){.sm\:size-6{width:calc(var(--spacing)*6);height:calc(var(--spacing)*6)}.sm\:size-16{width:calc(var(--spacing)*16);height:calc(var(--spacing)*16)}.sm\:pt-5{padding-top:calc(var(--spacing)*5)}}@media (width>=48rem){.md\:row-span-3{grid-row:span 3/span 3}}@media (width>=64rem){.lg\:col-start-2{grid-column-start:2}.lg\:h-16{height:calc(var(--spacing)*16)}.lg\:max-w-7xl{max-width:var(--container-7xl)}.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\:flex-col{flex-direction:column}.lg\:items-end{align-items:flex-end}.lg\:justify-center{justify-content:center}.lg\:gap-8{gap:calc(var(--spacing)*8)}.lg\:p-10{padding:calc(var(--spacing)*10)}.lg\:pt-0{padding-top:calc(var(--spacing)*0)}.lg\:pb-10{padding-bottom:calc(var(--spacing)*10)}.lg\:text-\[\#FF2D20\]{color:#ff2d20}}@media (prefers-color-scheme:dark){.dark\:block{display:block}.dark\:hidden{display:none}.dark\:bg-black{background-color:var(--color-black)}.dark\:bg-surface-900{background-color:color-mix(in srgb,var(--p-surface-900) 100%,transparent)}.dark\:bg-zinc-900{background-color:var(--color-zinc-900)}.dark\:via-zinc-900{--tw-gradient-via:var(--color-zinc-900);--tw-gradient-via-stops:var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-via)var(--tw-gradient-via-position),var(--tw-gradient-to)var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-via-stops)}.dark\:to-zinc-900{--tw-gradient-to:var(--color-zinc-900);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.dark\:text-white{color:var(--color-white)}.dark\:text-white\/50{color:color-mix(in oklab,var(--color-white)50%,transparent)}.dark\:text-white\/70{color:color-mix(in oklab,var(--color-white)70%,transparent)}.dark\:ring-zinc-800{--tw-ring-color:var(--color-zinc-800)}@media (hover:hover){.dark\:hover\:bg-surface-800:hover{background-color:color-mix(in srgb,var(--p-surface-800) 100%,transparent)}.dark\:hover\:text-white:hover{color:var(--color-white)}.dark\:hover\:text-white\/70:hover{color:color-mix(in oklab,var(--color-white)70%,transparent)}.dark\:hover\:text-white\/80:hover{color:color-mix(in oklab,var(--color-white)80%,transparent)}.dark\:hover\:ring-zinc-700:hover{--tw-ring-color:var(--color-zinc-700)}}.dark\:focus-visible\:ring-\[\#FF2D20\]:focus-visible{--tw-ring-color:#ff2d20}.dark\:focus-visible\:ring-white:focus-visible{--tw-ring-color:var(--color-white)}}}@keyframes enter{0%{opacity:var(--p-enter-opacity,1);transform:translate3d(var(--p-enter-translate-x,0),var(--p-enter-translate-y,0),0)scale3d(var(--p-enter-scale,1),var(--p-enter-scale,1),var(--p-enter-scale,1))rotate(var(--p-enter-rotate,0))}}@keyframes leave{to{opacity:var(--p-leave-opacity,1);transform:translate3d(var(--p-leave-translate-x,0),var(--p-leave-translate-y,0),0)scale3d(var(--p-leave-scale,1),var(--p-leave-scale,1),var(--p-leave-scale,1))rotate(var(--p-leave-rotate,0))}}@keyframes spin{to{transform:rotate(360deg)}}@keyframes ping{75%,to{opacity:0;transform:scale(2)}}@keyframes pulse{50%{opacity:.5}}@keyframes bounce{0%,to{animation-timing-function:cubic-bezier(.8,0,1,1);transform:translateY(-25%)}50%{animation-timing-function:cubic-bezier(0,0,.2,1);transform:none}}@keyframes fadein{0%{opacity:0}to{opacity:1}}@keyframes fadeout{0%{opacity:1}to{opacity:0}}@keyframes scalein{0%{opacity:0;transition:transform .12s cubic-bezier(0,0,.2,1),opacity .12s cubic-bezier(0,0,.2,1);transform:scaleY(.8)}to{opacity:1;transform:scaleY(1)}}@keyframes slidedown{0%{max-height:0}to{max-height:auto}}@keyframes slideup{0%{max-height:1000px}to{max-height:0}}@keyframes fadeinleft{0%{opacity:0;transition:transform .12s cubic-bezier(0,0,.2,1),opacity .12s cubic-bezier(0,0,.2,1);transform:translate(-100%)}to{opacity:1;transform:translate(0)}}@keyframes fadeoutleft{0%{opacity:1;transition:transform .12s cubic-bezier(0,0,.2,1),opacity .12s cubic-bezier(0,0,.2,1);transform:translate(0)}to{opacity:0;transform:translate(-100%)}}@keyframes fadeinright{0%{opacity:0;transition:transform .12s cubic-bezier(0,0,.2,1),opacity .12s cubic-bezier(0,0,.2,1);transform:translate(100%)}to{opacity:1;transform:translate(0)}}@keyframes fadeoutright{0%{opacity:1;transition:transform .12s cubic-bezier(0,0,.2,1),opacity .12s cubic-bezier(0,0,.2,1);transform:translate(0)}to{opacity:0;transform:translate(100%)}}@keyframes fadeinup{0%{opacity:0;transition:transform .12s cubic-bezier(0,0,.2,1),opacity .12s cubic-bezier(0,0,.2,1);transform:translateY(-100%)}to{opacity:1;transform:translateY(0)}}@keyframes fadeoutup{0%{opacity:1;transition:transform .12s cubic-bezier(0,0,.2,1),opacity .12s cubic-bezier(0,0,.2,1);transform:translateY(0)}to{opacity:0;transform:translateY(-100%)}}@keyframes fadeindown{0%{opacity:0;transition:transform .12s cubic-bezier(0,0,.2,1),opacity .12s cubic-bezier(0,0,.2,1);transform:translateY(100%)}to{opacity:1;transform:translateY(0)}}@keyframes fadeoutdown{0%{opacity:1;transition:transform .12s cubic-bezier(0,0,.2,1),opacity .12s cubic-bezier(0,0,.2,1);transform:translateY(0)}to{opacity:0;transform:translateY(100%)}}@keyframes width{0%{width:0}to{width:100%}}@keyframes flip{0%{transform:perspective(2000px)rotateX(-100deg)}to{transform:perspective(2000px)rotateX(0)}}@keyframes flipleft{0%{opacity:0;transform:perspective(2000px)rotateY(-100deg)}to{opacity:1;transform:perspective(2000px)rotateY(0)}}@keyframes flipright{0%{opacity:0;transform:perspective(2000px)rotateY(100deg)}to{opacity:1;transform:perspective(2000px)rotateY(0)}}@keyframes flipup{0%{opacity:0;transform:perspective(2000px)rotateX(-100deg)}to{opacity:1;transform:perspective(2000px)rotateX(0)}}@keyframes zoomin{0%{opacity:0;transform:scale3d(.3,.3,.3)}50%{opacity:1}}@keyframes zoomindown{0%{opacity:0;transform:scale3d(.1,.1,.1)translateY(-1000px)}60%{opacity:1;transform:scale3d(.475,.475,.475)translateY(60px)}}@keyframes zoominleft{0%{opacity:0;transform:scale3d(.1,.1,.1)translate(-1000px)}60%{opacity:1;transform:scale3d(.475,.475,.475)translate(10px)}}@keyframes zoominright{0%{opacity:0;transform:scale3d(.1,.1,.1)translate(1000px)}60%{opacity:1;transform:scale3d(.475,.475,.475)translate(-10px)}}@keyframes zoominup{0%{opacity:0;transform:scale3d(.1,.1,.1)translateY(1000px)}60%{opacity:1;transform:scale3d(.475,.475,.475)translateY(-60px)}}@property --tw-rotate-x{syntax:"*";inherits:false;initial-value:rotateX(0)}@property --tw-rotate-y{syntax:"*";inherits:false;initial-value:rotateY(0)}@property --tw-rotate-z{syntax:"*";inherits:false;initial-value:rotateZ(0)}@property --tw-skew-x{syntax:"*";inherits:false;initial-value:skewX(0)}@property --tw-skew-y{syntax:"*";inherits:false;initial-value:skewY(0)}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-gradient-position{syntax:"*";inherits:false}@property --tw-gradient-from{syntax:"";inherits:false;initial-value:#0000}@property --tw-gradient-via{syntax:"";inherits:false;initial-value:#0000}@property --tw-gradient-to{syntax:"";inherits:false;initial-value:#0000}@property --tw-gradient-stops{syntax:"*";inherits:false}@property --tw-gradient-via-stops{syntax:"*";inherits:false}@property --tw-gradient-from-position{syntax:"";inherits:false;initial-value:0%}@property --tw-gradient-via-position{syntax:"";inherits:false;initial-value:50%}@property --tw-gradient-to-position{syntax:"";inherits:false;initial-value:100%}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false} 2 | -------------------------------------------------------------------------------- /dist/build/assets/dayjs.min-NtYHfqg0.js: -------------------------------------------------------------------------------- 1 | import{r as ce,B as L,m as j,f as ue,k as be,z as he,h as H,A as Te,b as Oe,s as Pe,e as W,d as Ce,G as De,c as x,o as Y,F as q,a as fe,C as R,al as Me}from"./app-aQLUJyJ9.js";var se={};function we(t="pui_id_"){return se.hasOwnProperty(t)||(se[t]=0),se[t]++,`${t}${se[t]}`}var Q={_loadedStyleNames:new Set,getLoadedStyleNames:function(){return this._loadedStyleNames},isStyleNameLoaded:function(e){return this._loadedStyleNames.has(e)},setLoadedStyleName:function(e){this._loadedStyleNames.add(e)},deleteLoadedStyleName:function(e){this._loadedStyleNames.delete(e)},clearLoadedStyleNames:function(){this._loadedStyleNames.clear()}},me=L.extend({name:"common"});function te(t){"@babel/helpers - typeof";return te=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?function(e){return typeof e}:function(e){return e&&typeof Symbol=="function"&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},te(t)}function ke(t){return Se(t)||je(t)||$e(t)||ye()}function je(t){if(typeof Symbol<"u"&&t[Symbol.iterator]!=null||t["@@iterator"]!=null)return Array.from(t)}function X(t,e){return Se(t)||Ne(t,e)||$e(t,e)||ye()}function ye(){throw new TypeError(`Invalid attempt to destructure non-iterable instance. 2 | In order to be iterable, non-array objects must have a [Symbol.iterator]() method.`)}function $e(t,e){if(t){if(typeof t=="string")return pe(t,e);var n={}.toString.call(t).slice(8,-1);return n==="Object"&&t.constructor&&(n=t.constructor.name),n==="Map"||n==="Set"?Array.from(t):n==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?pe(t,e):void 0}}function pe(t,e){(e==null||e>t.length)&&(e=t.length);for(var n=0,r=Array(e);n1?n-1:0),o=1;o0&&arguments[0]!==void 0?arguments[0]:function(){};Q.clearLoadedStyleNames(),Pe.on("theme:change",e)},_getHostInstance:function(e){return e?this.$options.hostName?e.$.type.name===this.$options.hostName?e:this._getHostInstance(e.$parentInstance):e.$parentInstance:void 0},_getPropValue:function(e){var n;return this[e]||((n=this._getHostInstance(this))===null||n===void 0?void 0:n[e])},_getOptionValue:function(e){var n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:"",r=arguments.length>2&&arguments[2]!==void 0?arguments[2]:{};return Oe(e,n,r)},_getPTValue:function(){var e,n=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},r=arguments.length>1&&arguments[1]!==void 0?arguments[1]:"",o=arguments.length>2&&arguments[2]!==void 0?arguments[2]:{},f=arguments.length>3&&arguments[3]!==void 0?arguments[3]:!0,g=/./g.test(r)&&!!o[r.split(".")[0]],p=this._getPropValue("ptOptions")||((e=this.$primevueConfig)===null||e===void 0?void 0:e.ptOptions)||{},m=p.mergeSections,y=m===void 0?!0:m,h=p.mergeProps,$=h===void 0?!1:h,T=f?g?this._useGlobalPT(this._getPTClassValue,r,o):this._useDefaultPT(this._getPTClassValue,r,o):void 0,_=g?void 0:this._getPTSelf(n,this._getPTClassValue,r,v(v({},o),{},{global:T||{}})),D=this._getPTDatasets(r);return y||!y&&_?$?this._mergeProps($,T,_,D):v(v(v({},T),_),D):v(v({},_),D)},_getPTSelf:function(){for(var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},n=arguments.length,r=new Array(n>1?n-1:0),o=1;o0&&arguments[0]!==void 0?arguments[0]:"",o="data-pc-",f=r==="root"&&he((e=this.pt)===null||e===void 0?void 0:e["data-pc-section"]);return r!=="transition"&&v(v({},r==="root"&&v(v(ee({},"".concat(o,"name"),H(f?(n=this.pt)===null||n===void 0?void 0:n["data-pc-section"]:this.$.type.name)),f&&ee({},"".concat(o,"extend"),H(this.$.type.name))),Te()&&ee({},"".concat(this.$attrSelector),""))),{},ee({},"".concat(o,"section"),H(r)))},_getPTClassValue:function(){var e=this._getOptionValue.apply(this,arguments);return ue(e)||be(e)?{class:e}:e},_getPT:function(e){var n=this,r=arguments.length>1&&arguments[1]!==void 0?arguments[1]:"",o=arguments.length>2?arguments[2]:void 0,f=function(p){var m,y=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!1,h=o?o(p):p,$=H(r),T=H(n.$name);return(m=y?$!==T?h==null?void 0:h[$]:void 0:h==null?void 0:h[$])!==null&&m!==void 0?m:h};return e!=null&&e.hasOwnProperty("_usept")?{_usept:e._usept,originalValue:f(e.originalValue),value:f(e.value)}:f(e,!0)},_usePT:function(e,n,r,o){var f=function(N){return n(N,r,o)};if(e!=null&&e.hasOwnProperty("_usept")){var g,p=e._usept||((g=this.$primevueConfig)===null||g===void 0?void 0:g.ptOptions)||{},m=p.mergeSections,y=m===void 0?!0:m,h=p.mergeProps,$=h===void 0?!1:h,T=f(e.originalValue),_=f(e.value);return T===void 0&&_===void 0?void 0:ue(_)?_:ue(T)?T:y||!y&&_?$?this._mergeProps($,T,_):v(v({},T),_):_}return f(e)},_useGlobalPT:function(e,n,r){return this._usePT(this.globalPT,e,n,r)},_useDefaultPT:function(e,n,r){return this._usePT(this.defaultPT,e,n,r)},ptm:function(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:"",n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{};return this._getPTValue(this.pt,e,v(v({},this.$params),n))},ptmi:function(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:"",n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{};return j(this.$_attrsWithoutPT,this.ptm(e,n))},ptmo:function(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:"",r=arguments.length>2&&arguments[2]!==void 0?arguments[2]:{};return this._getPTValue(e,n,v({instance:this},r),!1)},cx:function(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:"",n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{};return this.isUnstyled?void 0:this._getOptionValue(this.$style.classes,e,v(v({},this.$params),n))},sx:function(){var e=arguments.length>0&&arguments[0]!==void 0?arguments[0]:"",n=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!0,r=arguments.length>2&&arguments[2]!==void 0?arguments[2]:{};if(n){var o=this._getOptionValue(this.$style.inlineStyles,e,v(v({},this.$params),r)),f=this._getOptionValue(me.inlineStyles,e,v(v({},this.$params),r));return[f,o]}}},computed:{globalPT:function(){var e,n=this;return this._getPT((e=this.$primevueConfig)===null||e===void 0?void 0:e.pt,void 0,function(r){return ce(r,{instance:n})})},defaultPT:function(){var e,n=this;return this._getPT((e=this.$primevueConfig)===null||e===void 0?void 0:e.pt,void 0,function(r){return n._getOptionValue(r,n.$name,v({},n.$params))||ce(r,v({},n.$params))})},isUnstyled:function(){var e;return this.unstyled!==void 0?this.unstyled:(e=this.$primevueConfig)===null||e===void 0?void 0:e.unstyled},$inProps:function(){var e,n=Object.keys(((e=this.$.vnode)===null||e===void 0?void 0:e.props)||{});return Object.fromEntries(Object.entries(this.$props).filter(function(r){var o=X(r,1),f=o[0];return n==null?void 0:n.includes(f)}))},$theme:function(){var e;return(e=this.$primevueConfig)===null||e===void 0?void 0:e.theme},$style:function(){return v(v({classes:void 0,inlineStyles:void 0,load:function(){},loadCSS:function(){},loadTheme:function(){}},(this._getHostInstance(this)||{}).$style),this.$options.style)},$styleOptions:function(){var e;return{nonce:(e=this.$primevueConfig)===null||e===void 0||(e=e.csp)===null||e===void 0?void 0:e.nonce}},$primevueConfig:function(){var e;return(e=this.$primevue)===null||e===void 0?void 0:e.config},$name:function(){return this.$options.hostName||this.$.type.name},$params:function(){var e=this._getHostInstance(this)||this.$parent;return{instance:this,props:this.$props,state:this.$data,attrs:this.$attrs,parent:{instance:e,props:e==null?void 0:e.$props,state:e==null?void 0:e.$data,attrs:e==null?void 0:e.$attrs}}},$_attrsPT:function(){return Object.entries(this.$attrs||{}).filter(function(e){var n=X(e,1),r=n[0];return r==null?void 0:r.startsWith("pt:")}).reduce(function(e,n){var r=X(n,2),o=r[0],f=r[1],g=o.split(":"),p=ke(g),m=p.slice(1);return m==null||m.reduce(function(y,h,$,T){return!y[h]&&(y[h]=$===T.length-1?f:{}),y[h]},e),e},{})},$_attrsWithoutPT:function(){return Object.entries(this.$attrs||{}).filter(function(e){var n=X(e,1),r=n[0];return!(r!=null&&r.startsWith("pt:"))}).reduce(function(e,n){var r=X(n,2),o=r[0],f=r[1];return e[o]=f,e},{})}}},Ae=function(e){var n=e.dt;return` 3 | .p-card { 4 | background: `.concat(n("card.background"),`; 5 | color: `).concat(n("card.color"),`; 6 | box-shadow: `).concat(n("card.shadow"),`; 7 | border-radius: `).concat(n("card.border.radius"),`; 8 | display: flex; 9 | flex-direction: column; 10 | } 11 | 12 | .p-card-caption { 13 | display: flex; 14 | flex-direction: column; 15 | gap: `).concat(n("card.caption.gap"),`; 16 | } 17 | 18 | .p-card-body { 19 | padding: `).concat(n("card.body.padding"),`; 20 | display: flex; 21 | flex-direction: column; 22 | gap: `).concat(n("card.body.gap"),`; 23 | } 24 | 25 | .p-card-title { 26 | font-size: `).concat(n("card.title.font.size"),`; 27 | font-weight: `).concat(n("card.title.font.weight"),`; 28 | } 29 | 30 | .p-card-subtitle { 31 | color: `).concat(n("card.subtitle.color"),`; 32 | } 33 | `)},Ee={root:"p-card p-component",header:"p-card-header",body:"p-card-body",caption:"p-card-caption",title:"p-card-title",subtitle:"p-card-subtitle",content:"p-card-content",footer:"p-card-footer"},Be=L.extend({name:"card",theme:Ae,classes:Ee}),Ue={name:"BaseCard",extends:Ie,style:Be,provide:function(){return{$pcCard:this,$parentInstance:this}}},He={name:"Card",extends:Ue,inheritAttrs:!1};function We(t,e,n,r,o,f){return Y(),x("div",j({class:t.cx("root")},t.ptmi("root")),[t.$slots.header?(Y(),x("div",j({key:0,class:t.cx("header")},t.ptm("header")),[R(t.$slots,"header")],16)):q("",!0),fe("div",j({class:t.cx("body")},t.ptm("body")),[t.$slots.title||t.$slots.subtitle?(Y(),x("div",j({key:0,class:t.cx("caption")},t.ptm("caption")),[t.$slots.title?(Y(),x("div",j({key:0,class:t.cx("title")},t.ptm("title")),[R(t.$slots,"title")],16)):q("",!0),t.$slots.subtitle?(Y(),x("div",j({key:1,class:t.cx("subtitle")},t.ptm("subtitle")),[R(t.$slots,"subtitle")],16)):q("",!0)],16)):q("",!0),fe("div",j({class:t.cx("content")},t.ptm("content")),[R(t.$slots,"content")],16),t.$slots.footer?(Y(),x("div",j({key:1,class:t.cx("footer")},t.ptm("footer")),[R(t.$slots,"footer")],16)):q("",!0)],16)],16)}He.render=We;var ae={exports:{}},xe=ae.exports,ge;function Ye(){return ge||(ge=1,function(t,e){(function(n,r){t.exports=r()})(xe,function(){var n=1e3,r=6e4,o=36e5,f="millisecond",g="second",p="minute",m="hour",y="day",h="week",$="month",T="quarter",_="year",D="date",N="Invalid Date",F=/^(\d{4})[-/]?(\d{1,2})?[-/]?(\d{0,2})[Tt\s]*(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?[.:]?(\d+)?$/,V=/\[([^\]]+)]|Y{1,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g,G={name:"en",weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),ordinal:function(l){var a=["th","st","nd","rd"],i=l%100;return"["+l+(a[(i-20)%10]||a[i]||a[0])+"]"}},z=function(l,a,i){var u=String(l);return!u||u.length>=a?l:""+Array(a+1-u.length).join(i)+l},_e={s:z,z:function(l){var a=-l.utcOffset(),i=Math.abs(a),u=Math.floor(i/60),s=i%60;return(a<=0?"+":"-")+z(u,2,"0")+":"+z(s,2,"0")},m:function l(a,i){if(a.date()1)return l(c[0])}else{var b=a.name;A[b]=a,s=b}return!u&&s&&(J=s),s||!u&&J},P=function(l,a){if(oe(l))return l.clone();var i=typeof a=="object"?a:{};return i.date=l,i.args=arguments,new re(i)},S=_e;S.l=ne,S.i=oe,S.w=function(l,a){return P(l,{locale:a.$L,utc:a.$u,x:a.$x,$offset:a.$offset})};var re=function(){function l(i){this.$L=ne(i.locale,null,!0),this.parse(i),this.$x=this.$x||i.x||{},this[le]=!0}var a=l.prototype;return a.parse=function(i){this.$d=function(u){var s=u.date,d=u.utc;if(s===null)return new Date(NaN);if(S.u(s))return new Date;if(s instanceof Date)return new Date(s);if(typeof s=="string"&&!/Z$/i.test(s)){var c=s.match(F);if(c){var b=c[2]-1||0,O=(c[7]||"0").substring(0,3);return d?new Date(Date.UTC(c[1],b,c[3]||1,c[4]||0,c[5]||0,c[6]||0,O)):new Date(c[1],b,c[3]||1,c[4]||0,c[5]||0,c[6]||0,O)}}return new Date(s)}(i),this.init()},a.init=function(){var i=this.$d;this.$y=i.getFullYear(),this.$M=i.getMonth(),this.$D=i.getDate(),this.$W=i.getDay(),this.$H=i.getHours(),this.$m=i.getMinutes(),this.$s=i.getSeconds(),this.$ms=i.getMilliseconds()},a.$utils=function(){return S},a.isValid=function(){return this.$d.toString()!==N},a.isSame=function(i,u){var s=P(i);return this.startOf(u)<=s&&s<=this.endOf(u)},a.isAfter=function(i,u){return P(i) 2 | 3 | 4 | 5 | 6 | #da532c 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /dist/favicons/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gearbox-solutions/mail-log/b0a93f0bcaaaf6d610bcfc81cd5e24673cce6eda/dist/favicons/favicon-16x16.png -------------------------------------------------------------------------------- /dist/favicons/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gearbox-solutions/mail-log/b0a93f0bcaaaf6d610bcfc81cd5e24673cce6eda/dist/favicons/favicon-32x32.png -------------------------------------------------------------------------------- /dist/favicons/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gearbox-solutions/mail-log/b0a93f0bcaaaf6d610bcfc81cd5e24673cce6eda/dist/favicons/favicon.ico -------------------------------------------------------------------------------- /dist/favicons/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gearbox-solutions/mail-log/b0a93f0bcaaaf6d610bcfc81cd5e24673cce6eda/dist/favicons/mstile-150x150.png -------------------------------------------------------------------------------- /dist/favicons/safari-pinned-tab.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | Created by potrace 1.14, written by Peter Selinger 2001-2017 9 | 10 | 12 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /docs/images/mail-log-detail.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gearbox-solutions/mail-log/b0a93f0bcaaaf6d610bcfc81cd5e24673cce6eda/docs/images/mail-log-detail.webp -------------------------------------------------------------------------------- /docs/images/mail-log-index.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gearbox-solutions/mail-log/b0a93f0bcaaaf6d610bcfc81cd5e24673cce6eda/docs/images/mail-log-index.webp -------------------------------------------------------------------------------- /resources/views/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gearbox-solutions/mail-log/b0a93f0bcaaaf6d610bcfc81cd5e24673cce6eda/resources/views/.gitkeep -------------------------------------------------------------------------------- /resources/views/app.blade.php: -------------------------------------------------------------------------------- 1 | @use('Illuminate\Support\Facades\Vite') 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | {{ config('app.name', 'Laravel') }} 10 | 11 | 12 | 13 | 14 | 15 | 16 | @routes 17 | 18 | {{ 19 | Vite::useHotFile(public_path('/mail-log-hot')) 20 | ->withEntryPoints(['resources/js/app.ts']) 21 | ->useBuildDirectory('') 22 | ->useManifestFilename('../vendor/gearbox-solutions/mail-log/dist/build/manifest.json') 23 | ->createAssetPathsUsing(function (string $path, ?bool $secure) { // Customize the backend path generation for built assets... 24 | return "/mail-log/build{$path}"; 25 | }) 26 | }} 27 | 28 | 29 | @inertiaHead 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | @inertia 48 | 49 | 50 | -------------------------------------------------------------------------------- /routes/web.php: -------------------------------------------------------------------------------- 1 | 'mail-log', 9 | 'middleware' => array_merge([ 10 | \GearboxSolutions\MailLog\Middleware\HandleInertiaRequests::class, 11 | ], config('mail-log.middleware', [])), 12 | ], function () { 13 | 14 | Route::get('/', [MailController::class, 'index'])->name('mail.index'); 15 | Route::get('/{id}', [MailController::class, 'show'])->name('mail.show'); 16 | 17 | // Serve the built front-end assets 18 | Route::get('/build/{path}', [AssetController::class, 'show'])->where('path', '.*'); 19 | // serve content in the favicons folder 20 | Route::get('/favicons/{path}', function ($path) { 21 | return response()->file(__DIR__.'/../dist/favicons/'.$path); 22 | }); 23 | 24 | }); 25 | -------------------------------------------------------------------------------- /src/Commands/DeleteAllMailLogsCommand.php: -------------------------------------------------------------------------------- 1 | info('No mail logs found to delete.'); 20 | 21 | return; 22 | } 23 | 24 | if ($this->confirm("Are you sure you want to delete all {$count} mail logs?")) { 25 | MailLog::truncate(); 26 | $this->info("{$count} mail log records have been deleted."); 27 | } else { 28 | $this->info('Operation cancelled.'); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Commands/DeleteOldMailLogsCommand.php: -------------------------------------------------------------------------------- 1 | option('yes'); 20 | } catch (\Throwable $th) { 21 | $skipConfirmation = false; 22 | } 23 | 24 | $days = (int) $this->argument('days'); 25 | $cutoffDate = Carbon::now()->subDays($days); 26 | 27 | $count = MailLog::where('sent_at', '<', $cutoffDate)->count(); 28 | 29 | if ($count === 0) { 30 | $this->info('No mail logs found older than '.$days.' days.'); 31 | 32 | return; 33 | } 34 | 35 | if ($skipConfirmation || $this->confirm("Are you sure you want to delete {$count} mail logs older than {$days} days?")) { 36 | $deleted = MailLog::where('sent_at', '<', $cutoffDate)->delete(); 37 | $this->info("{$deleted} mail logs have been deleted."); 38 | } else { 39 | $this->info('Operation cancelled.'); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Http/Controllers/AssetController.php: -------------------------------------------------------------------------------- 1 | 'application/javascript', 15 | 'css' => 'text/css', 16 | ]; 17 | 18 | $extension = pathinfo($path, PATHINFO_EXTENSION); 19 | $mimeType = $mimeTypes[$extension] ?? null; 20 | 21 | if (! file_exists($filePath)) { 22 | abort(404); 23 | } 24 | 25 | if ($mimeType) { 26 | return response()->file($filePath, ['Content-Type' => $mimeType]); 27 | } 28 | 29 | return response()->file($filePath); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Http/Controllers/MailController.php: -------------------------------------------------------------------------------- 1 | selectRaw('SUBSTRING(content_text, 1, 300) as content_text'); 16 | 17 | $search = $request->input('search'); 18 | $dates = $request->input('dates'); 19 | 20 | if ($search) { 21 | $mailQuery->where(function ($query) use ($search) { 22 | $query->where('subject', 'like', '%'.$search.'%') 23 | ->orWhere('to_email', 'like', $search.'%') 24 | ->orWhere('to_email_domain', 'like', $search.'%') 25 | ->orWhere('to_name', 'like', '%'.$search.'%'); 26 | }); 27 | } 28 | 29 | if (is_array($dates)) { 30 | $startDate = $dates[0]; 31 | // get the end date from the query, or if there's only one date, use the same day as the end date 32 | $endDate = $dates[1] ?? $dates[0]; 33 | $mailQuery->whereBetween('sent_at', [ 34 | date('Y-m-d 00:00:00', strtotime($startDate)), 35 | date('Y-m-d 23:59:59', strtotime($endDate)), 36 | ]); 37 | } 38 | 39 | $mail = $mailQuery->latest('sent_at')->paginate(25); 40 | 41 | $data = [ 42 | 'paginatedMail' => $mail, 43 | ]; 44 | 45 | return Inertia::render('Mail/MailIndex', $data); 46 | } 47 | 48 | public function show(Request $request, string $id) 49 | { 50 | $mail = MailLog::find($id); 51 | 52 | $data = [ 53 | 'mail' => $mail, 54 | ]; 55 | 56 | return Inertia::render('Mail/MailShow', $data); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Listeners/LogOutgoingMailListener.php: -------------------------------------------------------------------------------- 1 | message; 19 | $headers = $message->getHeaders(); 20 | 21 | // Get or generate Message-ID 22 | $messageId = $headers->get('Message-ID')?->getBodyAsString(); 23 | if (! $messageId) { 24 | $messageId = $headers->get('Message-Id')?->getBodyAsString(); 25 | } 26 | 27 | // generate a new message id if none is found 28 | if (! $messageId) { 29 | $messageId = Str::uuid(); 30 | 31 | // Store the messageId in the message instance 32 | $headers->addTextHeader('X-Mail-Log-Message-ID', $messageId); 33 | } 34 | 35 | // Remove angle brackets if present 36 | $messageId = trim($messageId, '<>'); 37 | 38 | $from_email = $this->formatAddresses($message->getFrom()); 39 | $to_email = $this->formatAddresses($message->getTo()); 40 | $to_email_domain = Str::after($to_email, '@'); 41 | $cc_email = $this->formatAddresses($message->getCc()); 42 | $bcc_email = $this->formatAddresses($message->getBcc()); 43 | $subject = $message->getSubject(); 44 | $contentHtml = $message->getHtmlBody(); 45 | $contentBody = $message->getTextBody(); 46 | $attachments = $message->getAttachments(); 47 | 48 | MailLog::create([ 49 | 'message_id' => $messageId, 50 | 'from_email' => $from_email, 51 | 'to_email' => $to_email, 52 | 'to_email_domain' => $to_email_domain, 53 | 'cc_email' => $cc_email, 54 | 'bcc_email' => $bcc_email, 55 | 'subject' => $subject, 56 | 'content_html' => $contentHtml, 57 | 'content_text' => $contentBody, 58 | 'status' => 'pending', 59 | 'sent_at' => now(), 60 | 'attachments' => $attachments, 61 | ]); 62 | } 63 | 64 | /** 65 | * Format email addresses array into string 66 | */ 67 | private function formatAddresses(?array $addresses): ?string 68 | { 69 | if (! $addresses) { 70 | return null; 71 | } 72 | 73 | return collect($addresses) 74 | ->map(function ($eachAddress, $index) { 75 | /** @var \Symfony\Component\Mime\Address $eachAddress */ 76 | $name = $eachAddress->getName(); 77 | $address = $eachAddress->getAddress(); 78 | 79 | return $name !== '' ? "$name <$address>" : $address; 80 | }) 81 | ->implode(', '); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/Listeners/UpdateEmailStatus.php: -------------------------------------------------------------------------------- 1 | message; 18 | $headers = $message->getHeaders(); 19 | 20 | // Get Message-ID 21 | $messageId = $headers->get('Message-ID')?->getBodyAsString(); 22 | if (! $messageId) { 23 | $messageId = $headers->get('Message-Id')?->getBodyAsString(); 24 | } 25 | 26 | if (! $messageId) { 27 | $messageId = $headers->get('X-Mail-Log-Message-ID')->getBodyAsString(); 28 | } 29 | 30 | // Remove angle brackets if present 31 | $messageId = trim($messageId, '<>'); 32 | 33 | // Find the email by message_id 34 | $mailLog = MailLog::where('message_id', $messageId) 35 | ->where('status', 'pending') 36 | ->first(); 37 | 38 | if ($mailLog) { 39 | $mailLog->update([ 40 | 'status' => 'sent', 41 | 'sent_at' => now(), 42 | ]); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Middleware/HandleInertiaRequests.php: -------------------------------------------------------------------------------- 1 | 35 | */ 36 | public function share(Request $request): array 37 | { 38 | $array = parent::share($request); 39 | 40 | return $array; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Models/MailLog.php: -------------------------------------------------------------------------------- 1 | setConnection($database); 19 | } 20 | 21 | protected static function newFactory() 22 | { 23 | return \GearboxSolutions\MailLog\Database\Factories\MailLogFactory::new(); 24 | } 25 | 26 | protected $guarded = [ 27 | 'id', 28 | 'created_at', 29 | 'updated_at', 30 | ]; 31 | 32 | protected $casts = [ 33 | 'sent_at' => 'datetime', 34 | 'headers' => 'array', 35 | 'body' => 'array', 36 | 'error_message' => 'array', 37 | 'created_at' => 'datetime', 38 | 'updated_at' => 'datetime', 39 | 'attachments' => 'array', 40 | ]; 41 | } 42 | -------------------------------------------------------------------------------- /src/Providers/MailLogServiceProvider.php: -------------------------------------------------------------------------------- 1 | configurationIsCached()) { 26 | $this->mergeConfigFrom( 27 | __DIR__.'/../../config/mail-log.php', 'mail-log' 28 | ); 29 | } 30 | 31 | } 32 | 33 | /** 34 | * Bootstrap services. 35 | * 36 | * @return void 37 | */ 38 | public function boot() 39 | { 40 | $this->loadViewsFrom(__DIR__.'/../../resources/views', 'mail-log'); 41 | $this->loadRoutesFrom(__DIR__.'/../../routes/web.php'); 42 | $this->publishesMigrations([ 43 | __DIR__.'/../../database/migrations' => database_path('migrations'), 44 | ], 'mail-log-migrations'); 45 | $this->publishes([ 46 | __DIR__.'/../../config/mail-log.php' => config_path('mail-log.php'), 47 | ], 'mail-log-config'); 48 | 49 | if ($this->app->runningInConsole()) { 50 | $this->commands([ 51 | DeleteAllMailLogsCommand::class, 52 | DeleteOldMailLogsCommand::class, 53 | ]); 54 | } 55 | 56 | // Register event listeners 57 | Event::listen(MessageSending::class, LogOutgoingMailListener::class); 58 | Event::listen(MessageSent::class, UpdateEmailStatus::class); 59 | } 60 | } 61 | --------------------------------------------------------------------------------