23-01-2026

This commit is contained in:
Kevin Adametz 2026-01-23 17:33:10 +01:00
parent 07959c0ba2
commit 854ce02bf6
166 changed files with 32909 additions and 1262 deletions

View file

@ -0,0 +1,102 @@
@php
if (! isset($scrollTo)) {
$scrollTo = 'body';
}
$scrollIntoViewJsSnippet = ($scrollTo !== false)
? <<<JS
(\$el.closest('{$scrollTo}') || document.querySelector('{$scrollTo}')).scrollIntoView()
JS
: '';
@endphp
<div>
@if ($paginator->hasPages())
<nav class="d-flex justify-items-center justify-content-between">
<div class="d-flex justify-content-between flex-fill d-sm-none">
<ul class="pagination">
{{-- Previous Page Link --}}
@if ($paginator->onFirstPage())
<li class="page-item disabled" aria-disabled="true">
<span class="page-link">@lang('pagination.previous')</span>
</li>
@else
<li class="page-item">
<button type="button" dusk="previousPage{{ $paginator->getPageName() == 'page' ? '' : '.' . $paginator->getPageName() }}" class="page-link" wire:click="previousPage('{{ $paginator->getPageName() }}')" x-on:click="{{ $scrollIntoViewJsSnippet }}" wire:loading.attr="disabled">@lang('pagination.previous')</button>
</li>
@endif
{{-- Next Page Link --}}
@if ($paginator->hasMorePages())
<li class="page-item">
<button type="button" dusk="nextPage{{ $paginator->getPageName() == 'page' ? '' : '.' . $paginator->getPageName() }}" class="page-link" wire:click="nextPage('{{ $paginator->getPageName() }}')" x-on:click="{{ $scrollIntoViewJsSnippet }}" wire:loading.attr="disabled">@lang('pagination.next')</button>
</li>
@else
<li class="page-item disabled" aria-disabled="true">
<span class="page-link" aria-hidden="true">@lang('pagination.next')</span>
</li>
@endif
</ul>
</div>
<div class="d-none flex-sm-fill d-sm-flex align-items-sm-center justify-content-sm-between">
<div>
<p class="small text-muted">
{!! __('Showing') !!}
<span class="fw-semibold">{{ $paginator->firstItem() }}</span>
{!! __('to') !!}
<span class="fw-semibold">{{ $paginator->lastItem() }}</span>
{!! __('of') !!}
<span class="fw-semibold">{{ $paginator->total() }}</span>
{!! __('results') !!}
</p>
</div>
<div>
<ul class="pagination">
{{-- Previous Page Link --}}
@if ($paginator->onFirstPage())
<li class="page-item disabled" aria-disabled="true" aria-label="@lang('pagination.previous')">
<span class="page-link" aria-hidden="true">&lsaquo;</span>
</li>
@else
<li class="page-item">
<button type="button" dusk="previousPage{{ $paginator->getPageName() == 'page' ? '' : '.' . $paginator->getPageName() }}" class="page-link" wire:click="previousPage('{{ $paginator->getPageName() }}')" x-on:click="{{ $scrollIntoViewJsSnippet }}" wire:loading.attr="disabled" aria-label="@lang('pagination.previous')">&lsaquo;</button>
</li>
@endif
{{-- Pagination Elements --}}
@foreach ($elements as $element)
{{-- "Three Dots" Separator --}}
@if (is_string($element))
<li class="page-item disabled" aria-disabled="true"><span class="page-link">{{ $element }}</span></li>
@endif
{{-- Array Of Links --}}
@if (is_array($element))
@foreach ($element as $page => $url)
@if ($page == $paginator->currentPage())
<li class="page-item active" wire:key="paginator-{{ $paginator->getPageName() }}-page-{{ $page }}" aria-current="page"><span class="page-link">{{ $page }}</span></li>
@else
<li class="page-item" wire:key="paginator-{{ $paginator->getPageName() }}-page-{{ $page }}"><button type="button" class="page-link" wire:click="gotoPage({{ $page }}, '{{ $paginator->getPageName() }}')" x-on:click="{{ $scrollIntoViewJsSnippet }}">{{ $page }}</button></li>
@endif
@endforeach
@endif
@endforeach
{{-- Next Page Link --}}
@if ($paginator->hasMorePages())
<li class="page-item">
<button type="button" dusk="nextPage{{ $paginator->getPageName() == 'page' ? '' : '.' . $paginator->getPageName() }}" class="page-link" wire:click="nextPage('{{ $paginator->getPageName() }}')" x-on:click="{{ $scrollIntoViewJsSnippet }}" wire:loading.attr="disabled" aria-label="@lang('pagination.next')">&rsaquo;</button>
</li>
@else
<li class="page-item disabled" aria-disabled="true" aria-label="@lang('pagination.next')">
<span class="page-link" aria-hidden="true">&rsaquo;</span>
</li>
@endif
</ul>
</div>
</div>
</nav>
@endif
</div>

View file

@ -0,0 +1,53 @@
@php
if (! isset($scrollTo)) {
$scrollTo = 'body';
}
$scrollIntoViewJsSnippet = ($scrollTo !== false)
? <<<JS
(\$el.closest('{$scrollTo}') || document.querySelector('{$scrollTo}')).scrollIntoView()
JS
: '';
@endphp
<div>
@if ($paginator->hasPages())
<nav>
<ul class="pagination">
{{-- Previous Page Link --}}
@if ($paginator->onFirstPage())
<li class="page-item disabled" aria-disabled="true">
<span class="page-link">@lang('pagination.previous')</span>
</li>
@else
@if(method_exists($paginator,'getCursorName'))
<li class="page-item">
<button dusk="previousPage" type="button" class="page-link" wire:key="cursor-{{ $paginator->getCursorName() }}-{{ $paginator->previousCursor()->encode() }}" wire:click="setPage('{{$paginator->previousCursor()->encode()}}','{{ $paginator->getCursorName() }}')" x-on:click="{{ $scrollIntoViewJsSnippet }}" wire:loading.attr="disabled">@lang('pagination.previous')</button>
</li>
@else
<li class="page-item">
<button type="button" dusk="previousPage{{ $paginator->getPageName() == 'page' ? '' : '.' . $paginator->getPageName() }}" class="page-link" wire:click="previousPage('{{ $paginator->getPageName() }}')" x-on:click="{{ $scrollIntoViewJsSnippet }}" wire:loading.attr="disabled">@lang('pagination.previous')</button>
</li>
@endif
@endif
{{-- Next Page Link --}}
@if ($paginator->hasMorePages())
@if(method_exists($paginator,'getCursorName'))
<li class="page-item">
<button dusk="nextPage" type="button" class="page-link" wire:key="cursor-{{ $paginator->getCursorName() }}-{{ $paginator->nextCursor()->encode() }}" wire:click="setPage('{{$paginator->nextCursor()->encode()}}','{{ $paginator->getCursorName() }}')" x-on:click="{{ $scrollIntoViewJsSnippet }}" wire:loading.attr="disabled">@lang('pagination.next')</button>
</li>
@else
<li class="page-item">
<button type="button" dusk="nextPage{{ $paginator->getPageName() == 'page' ? '' : '.' . $paginator->getPageName() }}" class="page-link" wire:click="nextPage('{{ $paginator->getPageName() }}')" x-on:click="{{ $scrollIntoViewJsSnippet }}" wire:loading.attr="disabled">@lang('pagination.next')</button>
</li>
@endif
@else
<li class="page-item disabled" aria-disabled="true">
<span class="page-link">@lang('pagination.next')</span>
</li>
@endif
</ul>
</nav>
@endif
</div>

View file

@ -0,0 +1,56 @@
@php
if (! isset($scrollTo)) {
$scrollTo = 'body';
}
$scrollIntoViewJsSnippet = ($scrollTo !== false)
? <<<JS
(\$el.closest('{$scrollTo}') || document.querySelector('{$scrollTo}')).scrollIntoView()
JS
: '';
@endphp
<div>
@if ($paginator->hasPages())
<nav role="navigation" aria-label="Pagination Navigation" class="flex justify-between">
<span>
{{-- Previous Page Link --}}
@if ($paginator->onFirstPage())
<span class="relative inline-flex items-center px-4 py-2 text-sm font-medium text-gray-500 bg-white border border-gray-300 cursor-default leading-5 rounded-md dark:text-gray-600 dark:bg-gray-800 dark:border-gray-600">
{!! __('pagination.previous') !!}
</span>
@else
@if(method_exists($paginator,'getCursorName'))
<button type="button" dusk="previousPage" wire:key="cursor-{{ $paginator->getCursorName() }}-{{ $paginator->previousCursor()->encode() }}" wire:click="setPage('{{$paginator->previousCursor()->encode()}}','{{ $paginator->getCursorName() }}')" x-on:click="{{ $scrollIntoViewJsSnippet }}" wire:loading.attr="disabled" class="relative inline-flex items-center px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 leading-5 rounded-md hover:text-gray-500 focus:outline-none focus:ring ring-blue-300 focus:border-blue-300 active:bg-gray-100 active:text-gray-700 transition ease-in-out duration-150 dark:bg-gray-800 dark:border-gray-600 dark:text-gray-300 dark:focus:border-blue-700 dark:active:bg-gray-700 dark:active:text-gray-300">
{!! __('pagination.previous') !!}
</button>
@else
<button
type="button" wire:click="previousPage('{{ $paginator->getPageName() }}')" x-on:click="{{ $scrollIntoViewJsSnippet }}" wire:loading.attr="disabled" dusk="previousPage{{ $paginator->getPageName() == 'page' ? '' : '.' . $paginator->getPageName() }}" class="relative inline-flex items-center px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 leading-5 rounded-md hover:text-gray-500 focus:outline-none focus:ring ring-blue-300 focus:border-blue-300 active:bg-gray-100 active:text-gray-700 transition ease-in-out duration-150 dark:bg-gray-800 dark:border-gray-600 dark:text-gray-300 dark:focus:border-blue-700 dark:active:bg-gray-700 dark:active:text-gray-300">
{!! __('pagination.previous') !!}
</button>
@endif
@endif
</span>
<span>
{{-- Next Page Link --}}
@if ($paginator->hasMorePages())
@if(method_exists($paginator,'getCursorName'))
<button type="button" dusk="nextPage" wire:key="cursor-{{ $paginator->getCursorName() }}-{{ $paginator->nextCursor()->encode() }}" wire:click="setPage('{{$paginator->nextCursor()->encode()}}','{{ $paginator->getCursorName() }}')" x-on:click="{{ $scrollIntoViewJsSnippet }}" wire:loading.attr="disabled" class="relative inline-flex items-center px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 leading-5 rounded-md hover:text-gray-500 focus:outline-none focus:ring ring-blue-300 focus:border-blue-300 active:bg-gray-100 active:text-gray-700 transition ease-in-out duration-150 dark:bg-gray-800 dark:border-gray-600 dark:text-gray-300 dark:focus:border-blue-700 dark:active:bg-gray-700 dark:active:text-gray-300">
{!! __('pagination.next') !!}
</button>
@else
<button type="button" wire:click="nextPage('{{ $paginator->getPageName() }}')" x-on:click="{{ $scrollIntoViewJsSnippet }}" wire:loading.attr="disabled" dusk="nextPage{{ $paginator->getPageName() == 'page' ? '' : '.' . $paginator->getPageName() }}" class="relative inline-flex items-center px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 leading-5 rounded-md hover:text-gray-500 focus:outline-none focus:ring ring-blue-300 focus:border-blue-300 active:bg-gray-100 active:text-gray-700 transition ease-in-out duration-150 dark:bg-gray-800 dark:border-gray-600 dark:text-gray-300 dark:focus:border-blue-700 dark:active:bg-gray-700 dark:active:text-gray-300">
{!! __('pagination.next') !!}
</button>
@endif
@else
<span class="relative inline-flex items-center px-4 py-2 text-sm font-medium text-gray-500 bg-white border border-gray-300 cursor-default leading-5 rounded-md dark:text-gray-600 dark:bg-gray-800 dark:border-gray-600">
{!! __('pagination.next') !!}
</span>
@endif
</span>
</nav>
@endif
</div>

View file

@ -0,0 +1,126 @@
@php
if (! isset($scrollTo)) {
$scrollTo = 'body';
}
$scrollIntoViewJsSnippet = ($scrollTo !== false)
? <<<JS
(\$el.closest('{$scrollTo}') || document.querySelector('{$scrollTo}')).scrollIntoView()
JS
: '';
@endphp
<div>
@if ($paginator->hasPages())
<nav role="navigation" aria-label="Pagination Navigation" class="flex items-center justify-between">
<div class="flex justify-between flex-1 sm:hidden">
<span>
@if ($paginator->onFirstPage())
<span class="relative inline-flex items-center px-4 py-2 text-sm font-medium text-gray-500 bg-white border border-gray-300 cursor-default leading-5 rounded-md dark:bg-gray-800 dark:border-gray-600 dark:text-gray-300 dark:focus:border-blue-700 dark:active:bg-gray-700 dark:active:text-gray-300">
{!! __('pagination.previous') !!}
</span>
@else
<button type="button" wire:click="previousPage('{{ $paginator->getPageName() }}')" x-on:click="{{ $scrollIntoViewJsSnippet }}" wire:loading.attr="disabled" dusk="previousPage{{ $paginator->getPageName() == 'page' ? '' : '.' . $paginator->getPageName() }}.before" class="relative inline-flex items-center px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 leading-5 rounded-md hover:text-gray-500 focus:outline-none focus:ring ring-blue-300 focus:border-blue-300 active:bg-gray-100 active:text-gray-700 transition ease-in-out duration-150 dark:bg-gray-800 dark:border-gray-600 dark:text-gray-300 dark:focus:border-blue-700 dark:active:bg-gray-700 dark:active:text-gray-300">
{!! __('pagination.previous') !!}
</button>
@endif
</span>
<span>
@if ($paginator->hasMorePages())
<button type="button" wire:click="nextPage('{{ $paginator->getPageName() }}')" x-on:click="{{ $scrollIntoViewJsSnippet }}" wire:loading.attr="disabled" dusk="nextPage{{ $paginator->getPageName() == 'page' ? '' : '.' . $paginator->getPageName() }}.before" class="relative inline-flex items-center px-4 py-2 ml-3 text-sm font-medium text-gray-700 bg-white border border-gray-300 leading-5 rounded-md hover:text-gray-500 focus:outline-none focus:ring ring-blue-300 focus:border-blue-300 active:bg-gray-100 active:text-gray-700 transition ease-in-out duration-150 dark:bg-gray-800 dark:border-gray-600 dark:text-gray-300 dark:focus:border-blue-700 dark:active:bg-gray-700 dark:active:text-gray-300">
{!! __('pagination.next') !!}
</button>
@else
<span class="relative inline-flex items-center px-4 py-2 ml-3 text-sm font-medium text-gray-500 bg-white border border-gray-300 cursor-default leading-5 rounded-md dark:text-gray-600 dark:bg-gray-800 dark:border-gray-600">
{!! __('pagination.next') !!}
</span>
@endif
</span>
</div>
<div class="hidden sm:flex-1 sm:flex sm:items-center sm:justify-between">
<div>
<p class="text-sm text-gray-700 leading-5 dark:text-gray-400">
<span>{!! __('Showing') !!}</span>
<span class="font-medium">{{ $paginator->firstItem() }}</span>
<span>{!! __('to') !!}</span>
<span class="font-medium">{{ $paginator->lastItem() }}</span>
<span>{!! __('of') !!}</span>
<span class="font-medium">{{ $paginator->total() }}</span>
<span>{!! __('results') !!}</span>
</p>
</div>
<div>
<span class="relative z-0 inline-flex rtl:flex-row-reverse rounded-md shadow-sm">
<span>
{{-- Previous Page Link --}}
@if ($paginator->onFirstPage())
<span aria-disabled="true" aria-label="{{ __('pagination.previous') }}">
<span class="relative inline-flex items-center px-2 py-2 text-sm font-medium text-gray-500 bg-white border border-gray-300 cursor-default rounded-l-md leading-5 dark:bg-gray-800 dark:border-gray-600" aria-hidden="true">
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z" clip-rule="evenodd" />
</svg>
</span>
</span>
@else
<button type="button" wire:click="previousPage('{{ $paginator->getPageName() }}')" x-on:click="{{ $scrollIntoViewJsSnippet }}" dusk="previousPage{{ $paginator->getPageName() == 'page' ? '' : '.' . $paginator->getPageName() }}.after" class="relative inline-flex items-center px-2 py-2 text-sm font-medium text-gray-500 bg-white border border-gray-300 rounded-l-md leading-5 hover:text-gray-400 focus:z-10 focus:outline-none focus:border-blue-300 focus:ring ring-blue-300 active:bg-gray-100 active:text-gray-500 transition ease-in-out duration-150 dark:bg-gray-800 dark:border-gray-600 dark:active:bg-gray-700 dark:focus:border-blue-800" aria-label="{{ __('pagination.previous') }}">
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z" clip-rule="evenodd" />
</svg>
</button>
@endif
</span>
{{-- Pagination Elements --}}
@foreach ($elements as $element)
{{-- "Three Dots" Separator --}}
@if (is_string($element))
<span aria-disabled="true">
<span class="relative inline-flex items-center px-4 py-2 -ml-px text-sm font-medium text-gray-700 bg-white border border-gray-300 cursor-default leading-5 dark:bg-gray-800 dark:border-gray-600 dark:text-gray-300">{{ $element }}</span>
</span>
@endif
{{-- Array Of Links --}}
@if (is_array($element))
@foreach ($element as $page => $url)
<span wire:key="paginator-{{ $paginator->getPageName() }}-page{{ $page }}">
@if ($page == $paginator->currentPage())
<span aria-current="page">
<span class="relative inline-flex items-center px-4 py-2 -ml-px text-sm font-medium text-gray-500 bg-white border border-gray-300 cursor-default leading-5 dark:bg-gray-800 dark:border-gray-600">{{ $page }}</span>
</span>
@else
<button type="button" wire:click="gotoPage({{ $page }}, '{{ $paginator->getPageName() }}')" x-on:click="{{ $scrollIntoViewJsSnippet }}" class="relative inline-flex items-center px-4 py-2 -ml-px text-sm font-medium text-gray-700 bg-white border border-gray-300 leading-5 hover:text-gray-500 focus:z-10 focus:outline-none focus:border-blue-300 focus:ring ring-blue-300 active:bg-gray-100 active:text-gray-700 transition ease-in-out duration-150 dark:bg-gray-800 dark:border-gray-600 dark:text-gray-400 dark:hover:text-gray-300 dark:active:bg-gray-700 dark:focus:border-blue-800" aria-label="{{ __('Go to page :page', ['page' => $page]) }}">
{{ $page }}
</button>
@endif
</span>
@endforeach
@endif
@endforeach
<span>
{{-- Next Page Link --}}
@if ($paginator->hasMorePages())
<button type="button" wire:click="nextPage('{{ $paginator->getPageName() }}')" x-on:click="{{ $scrollIntoViewJsSnippet }}" dusk="nextPage{{ $paginator->getPageName() == 'page' ? '' : '.' . $paginator->getPageName() }}.after" class="relative inline-flex items-center px-2 py-2 -ml-px text-sm font-medium text-gray-500 bg-white border border-gray-300 rounded-r-md leading-5 hover:text-gray-400 focus:z-10 focus:outline-none focus:border-blue-300 focus:ring ring-blue-300 active:bg-gray-100 active:text-gray-500 transition ease-in-out duration-150 dark:bg-gray-800 dark:border-gray-600 dark:active:bg-gray-700 dark:focus:border-blue-800" aria-label="{{ __('pagination.next') }}">
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd" />
</svg>
</button>
@else
<span aria-disabled="true" aria-label="{{ __('pagination.next') }}">
<span class="relative inline-flex items-center px-2 py-2 -ml-px text-sm font-medium text-gray-500 bg-white border border-gray-300 cursor-default rounded-r-md leading-5 dark:bg-gray-800 dark:border-gray-600" aria-hidden="true">
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd" />
</svg>
</span>
</span>
@endif
</span>
</span>
</div>
</div>
</nav>
@endif
</div>

View file

@ -0,0 +1,39 @@
@props([
'url',
'color' => 'primary',
'align' => 'center',
])
@php
$colorMap = [
'primary' => '#20a0da',
'blue' => '#20a0da',
'success' => '#22c55e',
'green' => '#22c55e',
'error' => '#dc2626',
'red' => '#dc2626',
];
$bgColor = $colorMap[$color] ?? '#20a0da';
@endphp
<table class="action" role="presentation" align="{{ $align }}" width="100%" cellpadding="0" cellspacing="0" border="0" style="margin: 30px 0;">
<tr>
<td align="{{ $align }}" style="padding: 0;">
<table role="presentation" width="auto" border="0" cellpadding="0" cellspacing="0" align="{{ $align }}">
<tr>
<td align="center" style="padding: 0;">
<!--[if mso]>
<v:roundrect xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="urn:schemas-microsoft-com:office:word" href="{{ $url }}" style="height:48px;v-text-anchor:middle;width:200px;" arcsize="10%" stroke="f" fillcolor="{{ $bgColor }}">
<w:anchorlock/>
<center style="color:#ffffff;font-family:Arial,Helvetica,sans-serif;font-size:16px;font-weight:bold;">
{!! $slot !!}
</center>
</v:roundrect>
<![endif]-->
<!--[if !mso]><!-->
<a href="{{ $url }}" class="button button-{{ $color }}" target="_blank" rel="noopener" style="background-color: {{ $bgColor }}; border-top: 14px solid {{ $bgColor }}; border-bottom: 14px solid {{ $bgColor }}; border-left: 32px solid {{ $bgColor }}; border-right: 32px solid {{ $bgColor }}; color: #ffffff; display: inline-block; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; font-size: 16px; font-weight: 600; line-height: 1; text-align: center; text-decoration: none; -webkit-text-size-adjust: none; mso-hide: all;">{!! $slot !!}</a>
<!--<![endif]-->
</td>
</tr>
</table>
</td>
</tr>
</table>

View file

@ -0,0 +1,21 @@
<tr>
<td style="padding: 0;">
<!--[if mso]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0" width="600" align="center">
<tr>
<td align="center">
<![endif]-->
<table class="footer" role="presentation" align="center" width="100%" cellpadding="0" cellspacing="0" border="0" style="max-width: 600px; margin: 0 auto;">
<tr>
<td class="content-cell" align="center" style="padding: 32px 20px; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; font-size: 13px; line-height: 1.6; color: #999999; text-align: center;">
{{ Illuminate\Mail\Markdown::parse($slot) }}
</td>
</tr>
</table>
<!--[if mso]>
</td>
</tr>
</table>
<![endif]-->
</td>
</tr>

View file

@ -0,0 +1,26 @@
@props(['url'])
@php
// Logo-URL für E-Mails (muss absolute URL sein, PNG für volle Kompatibilität)
$logoUrl = config('app.url') . '/img/logos/b2in-logo-negative.png';
@endphp
<tr>
<td class="header" style="background-color: #2b3f51; padding: 30px 20px; text-align: center;" bgcolor="#2b3f51" align="center">
<!--[if mso]>
<table role="presentation" border="0" cellpadding="0" cellspacing="0" width="100%">
<tr>
<td align="center" style="padding: 0;">
<![endif]-->
<a href="{{ $url }}" style="display: inline-block; text-decoration: none;" target="_blank" rel="noopener">
@if (trim($slot) === 'Laravel')
<img src="https://laravel.com/img/notification-logo-v2.1.png" class="logo" alt="Laravel Logo" width="50" height="50" style="display: block; height: 50px; max-height: 50px; width: auto; border: 0; outline: none;" />
@else
<img src="{{ $logoUrl }}" alt="{{ config('app.name') }}" width="140" height="40" style="display: block; height: 40px; max-height: 40px; width: auto; border: 0; outline: none; -ms-interpolation-mode: bicubic;" />
@endif
</a>
<!--[if mso]>
</td>
</tr>
</table>
<![endif]-->
</td>
</tr>

View file

@ -0,0 +1,178 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" lang="de">
<head>
<!--[if gte mso 9]>
<xml>
<o:OfficeDocumentSettings>
<o:AllowPNG/>
<o:PixelsPerInch>96</o:PixelsPerInch>
</o:OfficeDocumentSettings>
</xml>
<![endif]-->
<title>{{ config('app.name') }}</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="format-detection" content="telephone=no, date=no, address=no, email=no" />
<meta name="x-apple-disable-message-reformatting" />
<meta name="color-scheme" content="light dark" />
<meta name="supported-color-schemes" content="light dark" />
<!--[if mso]>
<style type="text/css">
body, table, td, th, p, a, h1, h2, h3, h4, h5, h6 {
font-family: Arial, Helvetica, sans-serif !important;
mso-line-height-rule: exactly;
}
</style>
<![endif]-->
<style type="text/css">
/* Reset & Base */
body, table, td, p, a, li, blockquote {
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
}
table, td {
mso-table-lspace: 0pt;
mso-table-rspace: 0pt;
border-collapse: collapse !important;
}
img {
-ms-interpolation-mode: bicubic;
border: 0;
height: auto;
line-height: 100%;
outline: none;
text-decoration: none;
}
body {
margin: 0 !important;
padding: 0 !important;
width: 100% !important;
height: 100% !important;
}
/* iOS Blue Links */
a[x-apple-data-detectors] {
color: inherit !important;
text-decoration: none !important;
font-size: inherit !important;
font-family: inherit !important;
font-weight: inherit !important;
line-height: inherit !important;
}
/* Gmail Blue Links */
u + #body a {
color: inherit;
text-decoration: none;
font-size: inherit;
font-family: inherit;
font-weight: inherit;
line-height: inherit;
}
/* Samsung Mail */
#MessageViewBody a {
color: inherit;
text-decoration: none;
font-size: inherit;
font-family: inherit;
font-weight: inherit;
line-height: inherit;
}
/* Dark Mode Styles */
:root {
color-scheme: light dark;
supported-color-schemes: light dark;
}
@media (prefers-color-scheme: dark) {
.dark-bg { background-color: #1a1a1a !important; }
.dark-bg-card { background-color: #2a2a2a !important; }
.dark-text { color: #ffffff !important; }
.dark-text-secondary { color: #e0e0e0 !important; }
.dark-border { border-color: #404040 !important; }
}
/* Responsive */
@media only screen and (max-width: 620px) {
.wrapper {
width: 100% !important;
max-width: 100% !important;
}
.inner-body {
width: 100% !important;
max-width: 100% !important;
}
.footer {
width: 100% !important;
max-width: 100% !important;
}
.content-cell {
padding: 24px 16px !important;
}
.button {
width: 100% !important;
max-width: 100% !important;
}
.mobile-full-width {
width: 100% !important;
display: block !important;
}
}
</style>
{!! $head ?? '' !!}
</head>
<body id="body" style="margin: 0; padding:0; width: 100%; height: 100%; background-color: #f5f4f2; -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%;" class="dark-bg">
<!--[if mso]>
<table role="presentation" border="0" cellspacing="0" cellpadding="0" width="100%" bgcolor="#f5f4f2">
<tr>
<td align="center">
<![endif]-->
<table class="wrapper" role="presentation" width="100%" cellpadding="0" cellspacing="0" border="0" style="background-color: #f5f4f2; margin: 0; padding: 0;" bgcolor="#f5f4f2">
<tr>
<td align="center" valign="top" style="padding: 0;">
<table class="content" role="presentation" width="100%" cellpadding="0" cellspacing="0" border="0" style="max-width: 600px; margin: 0 auto;">
{!! $header ?? '' !!}
<!-- Email Body -->
<tr>
<td class="body" style="background-color: #f5f4f2; padding: 30px 0 0 0;" bgcolor="#f5f4f2">
<!--[if mso]>
<table role="presentation" border="0" cellspacing="0" cellpadding="0" width="600" align="center">
<tr>
<td>
<![endif]-->
<table class="inner-body" role="presentation" align="center" width="100%" cellpadding="0" cellspacing="0" border="0" style="max-width: 600px; background-color: #ffffff; border-radius: 8px; margin: 0 auto;" bgcolor="#ffffff">
<!-- Body content -->
<tr>
<td class="content-cell dark-bg-card" style="padding: 40px; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; font-size: 16px; line-height: 1.6; color: #2a2a2a;">
{!! Illuminate\Mail\Markdown::parse($slot) !!}
{!! $subcopy ?? '' !!}
</td>
</tr>
</table>
<!--[if mso]>
</td>
</tr>
</table>
<![endif]-->
</td>
</tr>
{!! $footer ?? '' !!}
</table>
</td>
</tr>
</table>
<!--[if mso]>
</td>
</tr>
</table>
<![endif]-->
</body>
</html>

View file

@ -0,0 +1,36 @@
@component('mail::layout')
{{-- Header --}}
@slot('header')
@component('mail::header', ['url' => config('app.url')])
{{ config('app.name') }}
@endcomponent
@endslot
{{-- Body --}}
{!! $slot !!}
{{-- Subcopy --}}
@isset($subcopy)
@slot('subcopy')
@component('mail::subcopy')
{!! $subcopy !!}
@endcomponent
@endslot
@endisset
{{-- Footer --}}
@slot('footer')
@component('mail::footer')
&copy; {{ date('Y') }} {{ config('app.name') }}. {{ __('Alle Rechte vorbehalten.') }}
[{{ parse_url(config('app.url'), PHP_URL_HOST) }}]({{ config('app.url') }})
@endcomponent
@endslot
{{-- Theme CSS --}}
@slot('head')
<style type="text/css">
{!! file_get_contents(resource_path('views/vendor/mail/html/themes/b2in.css')) !!}
</style>
@endslot
@endcomponent

View file

@ -0,0 +1,13 @@
<table class="panel" role="presentation" width="100%" cellpadding="0" cellspacing="0" border="0" style="border-left: 4px solid #20a0da; margin: 24px 0;">
<tr>
<td class="panel-content" style="background-color: #f0f9ff; padding: 20px; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; font-size: 16px; line-height: 1.6; color: #2a2a2a;" bgcolor="#f0f9ff">
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" border="0">
<tr>
<td class="panel-item" style="padding: 0;">
{{ Illuminate\Mail\Markdown::parse($slot) }}
</td>
</tr>
</table>
</td>
</tr>
</table>

View file

@ -0,0 +1,7 @@
<table class="subcopy" role="presentation" width="100%" cellpadding="0" cellspacing="0" border="0" style="border-top: 1px solid #e0e0e0; margin-top: 30px; padding-top: 25px;">
<tr>
<td style="padding-top: 25px; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; font-size: 13px; line-height: 1.6; color: #606060;">
{{ Illuminate\Mail\Markdown::parse($slot) }}
</td>
</tr>
</table>

View file

@ -0,0 +1,9 @@
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" border="0" style="margin: 30px 0;">
<tr>
<td style="padding: 0;">
<div class="table" style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; font-size: 15px; line-height: 1.6; color: #2a2a2a;">
{{ Illuminate\Mail\Markdown::parse($slot) }}
</div>
</td>
</tr>
</table>

View file

@ -0,0 +1,468 @@
/* B2IN Mail Theme - E-Mail Client Optimized */
/* Primary: #2b3f51 (Anthracite) | Secondary: #20a0da (Dynamic Blue) */
/* Kompatibel mit: Outlook, Gmail, Apple Mail, Yahoo, Thunderbird */
/* ============================================
BASE STYLES
============================================ */
body,
body *:not(html):not(style):not(br):not(tr):not(code) {
box-sizing: border-box;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
position: relative;
}
body {
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
background-color: #f5f4f2;
color: #2a2a2a;
height: 100%;
line-height: 1.6;
margin: 0;
padding: 0;
width: 100% !important;
}
p,
ul,
ol,
blockquote {
line-height: 1.6;
text-align: left;
}
a {
color: #20a0da;
text-decoration: underline;
}
a img {
border: none;
}
/* ============================================
TYPOGRAPHY
============================================ */
h1 {
color: #2b3f51;
font-size: 24px;
font-weight: 700;
margin-top: 0;
margin-bottom: 16px;
text-align: left;
line-height: 1.3;
mso-line-height-rule: exactly;
}
h2 {
color: #2b3f51;
font-size: 20px;
font-weight: 600;
margin-top: 24px;
margin-bottom: 12px;
text-align: left;
line-height: 1.3;
mso-line-height-rule: exactly;
}
h3 {
color: #2b3f51;
font-size: 18px;
font-weight: 600;
margin-top: 20px;
margin-bottom: 10px;
text-align: left;
mso-line-height-rule: exactly;
}
p {
font-size: 16px;
line-height: 1.6;
margin-top: 0;
margin-bottom: 16px;
text-align: left;
color: #2a2a2a;
mso-line-height-rule: exactly;
}
p.sub {
font-size: 13px;
color: #606060;
}
strong {
color: #2b3f51;
font-weight: 600;
}
img {
max-width: 100%;
height: auto;
border: 0;
outline: none;
text-decoration: none;
-ms-interpolation-mode: bicubic;
}
/* ============================================
LAYOUT
============================================ */
.wrapper {
-premailer-cellpadding: 0;
-premailer-cellspacing: 0;
-premailer-width: 100%;
background-color: #f5f4f2;
margin: 0;
padding: 0;
width: 100%;
}
.content {
-premailer-cellpadding: 0;
-premailer-cellspacing: 0;
-premailer-width: 100%;
margin: 0;
padding: 0;
width: 100%;
}
/* ============================================
HEADER
============================================ */
.header {
padding: 30px 0;
text-align: center;
background-color: #2b3f51;
}
.header a {
color: #ffffff;
font-size: 24px;
font-weight: 700;
text-decoration: none;
letter-spacing: 0.5px;
}
/* ============================================
LOGO
============================================ */
.logo {
height: 50px;
margin-top: 0;
margin-bottom: 0;
max-height: 50px;
width: auto;
}
/* ============================================
BODY
============================================ */
.body {
-premailer-cellpadding: 0;
-premailer-cellspacing: 0;
-premailer-width: 100%;
background-color: #f5f4f2;
border-bottom: 1px solid #f5f4f2;
border-top: 1px solid #f5f4f2;
margin: 0;
padding: 0;
width: 100%;
}
.inner-body {
-premailer-cellpadding: 0;
-premailer-cellspacing: 0;
-premailer-width: 600px;
background-color: #ffffff;
border: 1px solid #e0e0e0;
margin: 0 auto;
padding: 0;
width: 600px;
max-width: 600px;
}
.inner-body a {
word-break: break-all;
}
/* ============================================
SUBCOPY
============================================ */
.subcopy {
border-top: 1px solid #e0e0e0;
margin-top: 30px;
padding-top: 25px;
}
.subcopy p {
font-size: 13px;
color: #606060;
}
/* ============================================
FOOTER
============================================ */
.footer {
-premailer-cellpadding: 0;
-premailer-cellspacing: 0;
-premailer-width: 600px;
margin: 0 auto;
padding: 32px 0;
text-align: center;
width: 600px;
}
.footer p {
color: #999999;
font-size: 13px;
text-align: center;
line-height: 1.6;
}
.footer a {
color: #20a0da;
text-decoration: underline;
}
/* ============================================
TABLES
============================================ */
.table table {
-premailer-cellpadding: 0;
-premailer-cellspacing: 0;
-premailer-width: 100%;
margin: 30px auto;
width: 100%;
border-collapse: collapse;
}
.table th {
border-bottom: 2px solid #e0e0e0;
color: #2b3f51;
font-weight: 600;
margin: 0;
padding: 10px;
text-align: left;
}
.table td {
color: #2a2a2a;
font-size: 15px;
line-height: 22px;
margin: 0;
padding: 12px 10px;
border-bottom: 1px solid #f0f0f0;
}
.content-cell {
max-width: 100vw;
padding: 40px;
}
/* ============================================
BUTTONS
============================================ */
.action {
-premailer-cellpadding: 0;
-premailer-cellspacing: 0;
-premailer-width: 100%;
margin: 30px auto;
padding: 0;
text-align: center;
width: 100%;
}
.button {
-webkit-text-size-adjust: none;
color: #ffffff;
display: inline-block;
overflow: hidden;
text-decoration: none;
font-weight: 600;
font-size: 16px;
letter-spacing: 0.3px;
}
.button-blue,
.button-primary {
background-color: #20a0da;
border-top: 14px solid #20a0da;
border-bottom: 14px solid #20a0da;
border-left: 32px solid #20a0da;
border-right: 32px solid #20a0da;
}
.button-green,
.button-success {
background-color: #22c55e;
border-top: 14px solid #22c55e;
border-bottom: 14px solid #22c55e;
border-left: 32px solid #22c55e;
border-right: 32px solid #22c55e;
}
.button-red,
.button-error {
background-color: #dc2626;
border-top: 14px solid #dc2626;
border-bottom: 14px solid #dc2626;
border-left: 32px solid #dc2626;
border-right: 32px solid #dc2626;
}
/* ============================================
PANELS
============================================ */
.panel {
border-left: 4px solid #20a0da;
margin: 24px 0;
}
.panel-content {
background-color: #f0f9ff;
color: #2a2a2a;
padding: 20px;
}
.panel-content p {
color: #2a2a2a;
margin-bottom: 0;
}
.panel-item {
padding: 0;
}
.panel-item p:last-of-type {
margin-bottom: 0;
padding-bottom: 0;
}
/* Special Panel Variants */
.panel-warning {
border-left-color: #f59e0b;
}
.panel-warning .panel-content {
background-color: #fffbeb;
}
.panel-success {
border-left-color: #22c55e;
}
.panel-success .panel-content {
background-color: #f0fdf4;
}
/* ============================================
PROMOTION
============================================ */
.promotion {
background-color: #2b3f51;
color: #ffffff;
margin: 0;
padding: 24px;
}
.promotion h1 {
color: #ffffff;
margin-top: 0;
}
.promotion p {
color: #e0e0e0;
}
/* ============================================
UTILITIES
============================================ */
.break-all {
word-break: break-all;
}
.text-center {
text-align: center !important;
}
/* ============================================
RESPONSIVE
============================================ */
@media only screen and (max-width: 620px) {
.inner-body {
width: 100% !important;
max-width: 100% !important;
}
.footer {
width: 100% !important;
max-width: 100% !important;
}
.content-cell {
padding: 24px 16px !important;
}
}
/* ============================================
DARK MODE SUPPORT
(Für E-Mail-Clients die es unterstützen)
============================================ */
@media (prefers-color-scheme: dark) {
body,
.wrapper,
.body {
background-color: #1a1a1a !important;
}
.inner-body {
background-color: #2a2a2a !important;
border-color: #404040 !important;
}
h1, h2, h3, strong {
color: #ffffff !important;
}
p, .table td {
color: #e0e0e0 !important;
}
.panel-content {
background-color: #1e3a5f !important;
}
.panel-content p {
color: #e0e0e0 !important;
}
.subcopy {
border-top-color: #404040 !important;
}
.table th {
color: #ffffff !important;
border-bottom-color: #404040 !important;
}
.table td {
border-bottom-color: #333333 !important;
}
}

View file

@ -0,0 +1,297 @@
/* Base */
body,
body *:not(html):not(style):not(br):not(tr):not(code) {
box-sizing: border-box;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif,
'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
position: relative;
}
body {
-webkit-text-size-adjust: none;
background-color: #ffffff;
color: #52525b;
height: 100%;
line-height: 1.4;
margin: 0;
padding: 0;
width: 100% !important;
}
p,
ul,
ol,
blockquote {
line-height: 1.4;
text-align: left;
}
a {
color: #18181b;
}
a img {
border: none;
}
/* Typography */
h1 {
color: #18181b;
font-size: 18px;
font-weight: bold;
margin-top: 0;
text-align: left;
}
h2 {
font-size: 16px;
font-weight: bold;
margin-top: 0;
text-align: left;
}
h3 {
font-size: 14px;
font-weight: bold;
margin-top: 0;
text-align: left;
}
p {
font-size: 16px;
line-height: 1.5em;
margin-top: 0;
text-align: left;
}
p.sub {
font-size: 12px;
}
img {
max-width: 100%;
}
/* Layout */
.wrapper {
-premailer-cellpadding: 0;
-premailer-cellspacing: 0;
-premailer-width: 100%;
background-color: #fafafa;
margin: 0;
padding: 0;
width: 100%;
}
.content {
-premailer-cellpadding: 0;
-premailer-cellspacing: 0;
-premailer-width: 100%;
margin: 0;
padding: 0;
width: 100%;
}
/* Header */
.header {
padding: 25px 0;
text-align: center;
}
.header a {
color: #18181b;
font-size: 19px;
font-weight: bold;
text-decoration: none;
}
/* Logo */
.logo {
height: 75px;
margin-top: 15px;
margin-bottom: 10px;
max-height: 75px;
width: 75px;
}
/* Body */
.body {
-premailer-cellpadding: 0;
-premailer-cellspacing: 0;
-premailer-width: 100%;
background-color: #fafafa;
border-bottom: 1px solid #fafafa;
border-top: 1px solid #fafafa;
margin: 0;
padding: 0;
width: 100%;
}
.inner-body {
-premailer-cellpadding: 0;
-premailer-cellspacing: 0;
-premailer-width: 570px;
background-color: #ffffff;
border-color: #e4e4e7;
border-radius: 4px;
border-width: 1px;
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1);
margin: 0 auto;
padding: 0;
width: 570px;
}
.inner-body a {
word-break: break-all;
}
/* Subcopy */
.subcopy {
border-top: 1px solid #e4e4e7;
margin-top: 25px;
padding-top: 25px;
}
.subcopy p {
font-size: 14px;
}
/* Footer */
.footer {
-premailer-cellpadding: 0;
-premailer-cellspacing: 0;
-premailer-width: 570px;
margin: 0 auto;
padding: 0;
text-align: center;
width: 570px;
}
.footer p {
color: #a1a1aa;
font-size: 12px;
text-align: center;
}
.footer a {
color: #a1a1aa;
text-decoration: underline;
}
/* Tables */
.table table {
-premailer-cellpadding: 0;
-premailer-cellspacing: 0;
-premailer-width: 100%;
margin: 30px auto;
width: 100%;
}
.table th {
border-bottom: 1px solid #e4e4e7;
margin: 0;
padding-bottom: 8px;
}
.table td {
color: #52525b;
font-size: 15px;
line-height: 18px;
margin: 0;
padding: 10px 0;
}
.content-cell {
max-width: 100vw;
padding: 32px;
}
/* Buttons */
.action {
-premailer-cellpadding: 0;
-premailer-cellspacing: 0;
-premailer-width: 100%;
margin: 30px auto;
padding: 0;
text-align: center;
width: 100%;
float: unset;
}
.button {
-webkit-text-size-adjust: none;
border-radius: 4px;
color: #fff;
display: inline-block;
overflow: hidden;
text-decoration: none;
}
.button-blue,
.button-primary {
background-color: #18181b;
border-bottom: 8px solid #18181b;
border-left: 18px solid #18181b;
border-right: 18px solid #18181b;
border-top: 8px solid #18181b;
}
.button-green,
.button-success {
background-color: #16a34a;
border-bottom: 8px solid #16a34a;
border-left: 18px solid #16a34a;
border-right: 18px solid #16a34a;
border-top: 8px solid #16a34a;
}
.button-red,
.button-error {
background-color: #dc2626;
border-bottom: 8px solid #dc2626;
border-left: 18px solid #dc2626;
border-right: 18px solid #dc2626;
border-top: 8px solid #dc2626;
}
/* Panels */
.panel {
border-left: #18181b solid 4px;
margin: 21px 0;
}
.panel-content {
background-color: #fafafa;
color: #52525b;
padding: 16px;
}
.panel-content p {
color: #52525b;
}
.panel-item {
padding: 0;
}
.panel-item p:last-of-type {
margin-bottom: 0;
padding-bottom: 0;
}
/* Utilities */
.break-all {
word-break: break-all;
}

View file

@ -0,0 +1 @@
{{ $slot }}: {{ $url }}

View file

@ -0,0 +1 @@
{{ $slot }}

View file

@ -0,0 +1 @@
{{ $slot }}: {{ $url }}

View file

@ -0,0 +1,9 @@
{!! strip_tags($header ?? '') !!}
{!! strip_tags($slot) !!}
@isset($subcopy)
{!! strip_tags($subcopy) !!}
@endisset
{!! strip_tags($footer ?? '') !!}

View file

@ -0,0 +1,27 @@
<x-mail::layout>
{{-- Header --}}
<x-slot:header>
<x-mail::header :url="config('app.url')">
{{ config('app.name') }}
</x-mail::header>
</x-slot:header>
{{-- Body --}}
{{ $slot }}
{{-- Subcopy --}}
@isset($subcopy)
<x-slot:subcopy>
<x-mail::subcopy>
{{ $subcopy }}
</x-mail::subcopy>
</x-slot:subcopy>
@endisset
{{-- Footer --}}
<x-slot:footer>
<x-mail::footer>
© {{ date('Y') }} {{ config('app.name') }}. @lang('All rights reserved.')
</x-mail::footer>
</x-slot:footer>
</x-mail::layout>

View file

@ -0,0 +1 @@
{{ $slot }}

View file

@ -0,0 +1 @@
{{ $slot }}

View file

@ -0,0 +1 @@
{{ $slot }}