Skip to content

Commit 84d3b25

Browse files
authored
Merge pull request #73 from backstagephp/fix/auto-register-mail-routes
Fix mail routes, preview improvements & formatted HTML tab
2 parents d837248 + 53730bc commit 84d3b25

File tree

7 files changed

+121
-16
lines changed

7 files changed

+121
-16
lines changed
Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
11
@php
2-
$attachment = $getState();
3-
$mailId = is_object($attachment) ? $attachment->mail_id : null;
2+
$uuid = $getState();
3+
$attachmentModel = config('mails.models.attachment', \Backstage\Mails\Laravel\Models\MailAttachment::class);
4+
$attachment = $uuid ? $attachmentModel::where('uuid', $uuid)->first() : null;
5+
$mailId = $attachment?->mail_id;
46
@endphp
57

68
@if($mailId && $attachment)
7-
<a type="button"
8-
href="{{ route('filament.' . Filament\Facades\Filament::getCurrentPanel()->getId() . '.mails.attachment.download', [
9+
<a href="{{ route('filament.' . Filament\Facades\Filament::getCurrentPanel()->getId() . '.mails.attachment.download', [
910
'tenant' => Filament\Facades\Filament::getTenant(),
1011
'mail' => $mailId,
1112
'attachment' => $attachment->id,
1213
'filename' => $attachment->filename,
1314
]) }}"
14-
class="rounded-md bg-white px-3.5 py-2.5 text-sm font-semibold cursor-pointer text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50">Download</a>
15+
class="fi-btn fi-btn-size-sm inline-flex items-center justify-center gap-1 rounded-lg bg-primary-600 px-3 py-1.5 text-sm font-semibold text-white shadow-sm transition-colors hover:bg-primary-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary-600 dark:bg-primary-500 dark:hover:bg-primary-400">
16+
<x-filament::icon icon="heroicon-m-arrow-down-tray" class="h-4 w-4" />
17+
Download
18+
</a>
1519
@endif
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
@php
2+
$formatted = trim($html);
3+
4+
// Put each tag on its own line
5+
$formatted = preg_replace('/>\s*</', ">\n<", $formatted);
6+
7+
// Indent based on nesting depth
8+
$lines = explode("\n", $formatted);
9+
$indent = 0;
10+
$result = [];
11+
$selfClosingPattern = '/^<(?:meta|link|br|hr|img|input|source|col|area|base|embed|param|track|wbr)\b/i';
12+
$closingPattern = '/^<\//';
13+
$openingPattern = '/^<[a-zA-Z]/';
14+
15+
foreach ($lines as $line) {
16+
$line = trim($line);
17+
18+
if ($line === '') {
19+
continue;
20+
}
21+
22+
if (preg_match($closingPattern, $line)) {
23+
$indent = max(0, $indent - 1);
24+
}
25+
26+
$result[] = str_repeat(' ', $indent) . $line;
27+
28+
if (preg_match($openingPattern, $line)
29+
&& !preg_match($selfClosingPattern, $line)
30+
&& !preg_match($closingPattern, $line)
31+
&& !str_contains($line, '/>')
32+
&& !preg_match('/<\/[a-zA-Z][^>]*>\s*$/', $line)
33+
) {
34+
$indent++;
35+
}
36+
}
37+
38+
$formatted = implode("\n", $result);
39+
@endphp
40+
41+
<div class="prose prose-sm sm:prose lg:prose-lg xl:prose-2xl max-w-full overflow-x-auto">
42+
<pre class="whitespace-pre-wrap break-words"><code class="language-html">{{ $formatted }}</code></pre>
43+
</div>
Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
11
<div class="prose prose-sm sm:prose lg:prose-lg xl:prose-2xl max-w-full overflow-x-auto">
2-
<pre class="whitespace-pre-wrap break-words">
3-
<code class="language-html">{{ $html }}</code>
4-
</pre>
2+
<pre class="whitespace-pre-wrap break-words"><code class="language-html">{{ trim($html) }}</code></pre>
53
</div>
Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
1-
<div class="w-full h-screen">
1+
<div class="w-full" x-data="{ height: '250px' }" x-on:message.window="
2+
if ($event.data && $event.data.type === 'mails-iframe-resize' && $event.data.mailId === '{{ $mail->id }}') {
3+
height = $event.data.height + 'px';
4+
}
5+
">
26
<iframe
37
src="{{ route('filament.' . Filament\Facades\Filament::getCurrentPanel()->getId() . '.mails.preview', ['tenant' => Filament\Facades\Filament::getTenant(), 'mail' => $mail->id]) }}"
4-
class="w-full h-full max-w-full" style="width: 100vw; height: 100vh; border: none;">
8+
class="w-full border-none"
9+
x-bind:style="'height: ' + height">
510
</iframe>
611
</div>

src/Controllers/MailPreviewController.php

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,20 @@ public function __invoke(Request $request)
1313
/** @var Mail $mail */
1414
$mail = Mail::find($request->mail);
1515

16-
return response($mail->html);
16+
$resizeScript = <<<HTML
17+
<script>
18+
function postHeight() {
19+
var height = document.documentElement.scrollHeight || document.body.scrollHeight;
20+
window.parent.postMessage({ type: 'mails-iframe-resize', mailId: '{$mail->id}', height: height }, '*');
21+
}
22+
window.addEventListener('load', postHeight);
23+
window.addEventListener('resize', postHeight);
24+
new MutationObserver(postHeight).observe(document.body, { childList: true, subtree: true });
25+
</script>
26+
HTML;
27+
28+
$html = $mail->html . $resizeScript;
29+
30+
return response($html);
1731
}
1832
}

src/Resources/MailResource.php

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,21 @@ public static function infolist(Schema $schema): Schema
278278
->label(__('HTML Content'))
279279
->columnSpanFull(),
280280
]),
281+
Tab::make('HTML (Formatted)')
282+
->schema([
283+
TextEntry::make('html')
284+
->hiddenLabel()
285+
->extraAttributes(['class' => 'overflow-x-auto'])
286+
->formatStateUsing(fn (string $state, Mail $record): View => view(
287+
'mails::mails.html-formatted',
288+
['html' => $state, 'mail' => $record],
289+
))
290+
->copyable()
291+
->copyMessage('Copied!')
292+
->copyMessageDuration(1500)
293+
->label(__('HTML Content (Formatted)'))
294+
->columnSpanFull(),
295+
]),
281296
Tab::make('Text')
282297
->schema([
283298
TextEntry::make('text')
@@ -286,7 +301,7 @@ public static function infolist(Schema $schema): Schema
286301
->copyMessage('Copied!')
287302
->copyMessageDuration(1500)
288303
->label(__('Text Content'))
289-
->formatStateUsing(fn (string $state): HtmlString => new HtmlString(nl2br(e($state))))
304+
->formatStateUsing(fn (string $state): HtmlString => new HtmlString('<code>' . nl2br(e($state)) . '</code>'))
290305
->columnSpanFull(),
291306
]),
292307
])->columnSpanFull(),
@@ -308,17 +323,22 @@ public static function infolist(Schema $schema): Schema
308323
->label(__('Attachments'))
309324
->visible(fn (Mail $record) => $record->attachments->count() > 0)
310325
->schema([
311-
Grid::make(3)
326+
Grid::make(4)
312327
->schema([
313328
TextEntry::make('filename')
314329
->label(__('Name')),
315330
TextEntry::make('size')
316-
->label(__('Size')),
331+
->label(__('Size'))
332+
->formatStateUsing(fn (int $state): string => match (true) {
333+
$state >= 1073741824 => number_format($state / 1073741824, 2) . ' GB',
334+
$state >= 1048576 => number_format($state / 1048576, 2) . ' MB',
335+
$state >= 1024 => number_format($state / 1024, 2) . ' KB',
336+
default => $state . ' bytes',
337+
}),
317338
TextEntry::make('mime')
318339
->label(__('Mime Type')),
319340
ViewEntry::make('uuid')
320341
->label(__('Download'))
321-
->formatStateUsing(fn ($record) => $record)
322342
->view('mails::mails.download'),
323343
]),
324344
]),
@@ -392,7 +412,6 @@ public static function table(Table $table): Table
392412
])
393413
->recordActions([
394414
ViewAction::make()
395-
// ->url(null)
396415
->modal()
397416
->slideOver()
398417
->label(__('View'))

src/Resources/MailResource/Pages/ListMails.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,28 @@ public static function canAccess(array $parameters = []): bool
1717
return MailsPlugin::get()->userCanManageMails();
1818
}
1919

20+
public function mountAction(string $name, array $arguments = [], array $context = []): mixed
21+
{
22+
$result = parent::mountAction($name, $arguments, $context);
23+
24+
if ($name === 'view' && isset($context['table']) && isset($context['recordKey'])) {
25+
$this->defaultTableAction = $name;
26+
$this->defaultTableActionRecord = $context['recordKey'];
27+
}
28+
29+
return $result;
30+
}
31+
32+
public function unmountAction(bool $canCancelParentActions = true): void
33+
{
34+
parent::unmountAction($canCancelParentActions);
35+
36+
if (empty($this->mountedActions)) {
37+
$this->defaultTableAction = null;
38+
$this->defaultTableActionRecord = null;
39+
}
40+
}
41+
2042
public static function getResource(): string
2143
{
2244
return config('mails.resources.mail', MailResource::class);

0 commit comments

Comments
 (0)