diff --git a/app/Livewire/Project/Application/Deployment/Index.php b/app/Livewire/Project/Application/Deployment/Index.php
index 1625e9f08..fb24414cd 100644
--- a/app/Livewire/Project/Application/Deployment/Index.php
+++ b/app/Livewire/Project/Application/Deployment/Index.php
@@ -22,6 +22,14 @@ class Index extends Component
public int $defaultTake = 10;
+ public function updatedDefaultTake(): void
+ {
+ $this->defaultTake = max(1, min(100, $this->defaultTake));
+
+ $this->skip = 0;
+ $this->loadDeployments();
+ }
+
public bool $showNext = false;
public bool $showPrev = false;
diff --git a/app/Livewire/Project/Shared/EnvironmentVariable/All.php b/app/Livewire/Project/Shared/EnvironmentVariable/All.php
index f5516d2a1..ea8394c1b 100644
--- a/app/Livewire/Project/Shared/EnvironmentVariable/All.php
+++ b/app/Livewire/Project/Shared/EnvironmentVariable/All.php
@@ -44,6 +44,14 @@ class All extends Component
public int $perPage = 10;
+ public function updatedPerPage(): void
+ {
+ $this->perPage = max(1, min(100, $this->perPage));
+
+ $this->page = 1;
+ $this->clearEnvironmentVariableCaches();
+ }
+
public bool $is_env_sorting_enabled = false;
public bool $use_build_secrets = false;
diff --git a/app/Livewire/Project/Shared/Storages/VolumeBackups.php b/app/Livewire/Project/Shared/Storages/VolumeBackups.php
index d361f90ca..a03820b4b 100644
--- a/app/Livewire/Project/Shared/Storages/VolumeBackups.php
+++ b/app/Livewire/Project/Shared/Storages/VolumeBackups.php
@@ -58,6 +58,15 @@ class VolumeBackups extends Component
public int $timeout = 3600;
+ public int $perPage = 10;
+
+ public function updatedPerPage(): void
+ {
+ $this->perPage = max(1, min(100, $this->perPage));
+
+ $this->resetPage();
+ }
+
public bool $delete_backup_s3 = false;
public Collection $availableS3Storages;
@@ -316,7 +325,7 @@ class VolumeBackups extends Component
public function render()
{
- $executions = $this->backup?->executions()->paginate(10);
+ $executions = $this->backup?->executions()->paginate($this->perPage);
return view('livewire.project.shared.storages.volume-backups', [
'executions' => $executions ?? collect(),
diff --git a/app/Livewire/Team/AdminView.php b/app/Livewire/Team/AdminView.php
index 5403fa90d..e60902975 100644
--- a/app/Livewire/Team/AdminView.php
+++ b/app/Livewire/Team/AdminView.php
@@ -16,6 +16,8 @@ class AdminView extends Component
public string $sort = 'name_asc';
+ public int $perPage = 10;
+
public function mount()
{
if (! isInstanceAdmin()) {
@@ -42,6 +44,13 @@ class AdminView extends Component
$this->resetPage();
}
+ public function updatedPerPage(): void
+ {
+ $this->perPage = max(1, min(100, $this->perPage));
+
+ $this->resetPage();
+ }
+
public function submitSearch(): void
{
if (! isInstanceAdmin()) {
@@ -103,7 +112,7 @@ class AdminView extends Component
->when($this->sort === 'email_desc', fn ($query) => $query->orderByDesc('email'))
->when($this->sort === 'name_asc', fn ($query) => $query->orderBy('name'))
->orderBy('id')
- ->paginate(10);
+ ->paginate($this->perPage);
return view('livewire.team.admin-view', [
'users' => $users,
diff --git a/resources/css/app.css b/resources/css/app.css
index 059044436..ccaf7181e 100644
--- a/resources/css/app.css
+++ b/resources/css/app.css
@@ -1939,6 +1939,28 @@ html[data-theme="custom"] textarea:disabled {
box-shadow: 0 12px 32px rgba(0, 0, 0, 0.45);
}
+.floating-dropdown-panel {
+ min-width: 0;
+}
+
+/* Older menus still render inside their page container. On mobile, keep
+ those panels fully visible until they are migrated to the portaled
+ dropdown component. Portaled panels carry their own fixed coordinates. */
+@media (max-width: 767px) {
+ .listbox-panel:not([style*="position: fixed"]) {
+ position: fixed !important;
+ top: 50% !important;
+ right: auto !important;
+ left: 50% !important;
+ width: max-content;
+ max-width: calc(100vw - 1.5rem) !important;
+ max-height: calc(100dvh - 1.5rem) !important;
+ box-sizing: border-box;
+ transform: translate(-50%, -50%) !important;
+ z-index: 9999 !important;
+ }
+}
+
.listbox-option {
display: flex;
align-items: center;
diff --git a/resources/views/components/client-pagination.blade.php b/resources/views/components/client-pagination.blade.php
new file mode 100644
index 000000000..924ec6e74
--- /dev/null
+++ b/resources/views/components/client-pagination.blade.php
@@ -0,0 +1,29 @@
+@props([
+ 'summary',
+ 'pageSizeModel',
+ 'storageKey',
+ 'options' => [10, 25, 50, 100],
+ 'previousAction' => 'page = Math.max(1, page - 1)',
+ 'nextAction' => 'page = Math.min(totalPages, page + 1)',
+ 'previousDisabled' => 'page === 1',
+ 'nextDisabled' => 'page >= totalPages',
+])
+
+
diff --git a/resources/views/components/dropdown.blade.php b/resources/views/components/dropdown.blade.php
index b48b04143..d466f3907 100644
--- a/resources/views/components/dropdown.blade.php
+++ b/resources/views/components/dropdown.blade.php
@@ -25,13 +25,10 @@
const triggerRect = this.$refs.trigger.getBoundingClientRect();
const panelRect = this.$refs.panel.getBoundingClientRect();
const viewportPadding = 8;
- let left = triggerRect.left;
-
- if ((left + panelRect.width + viewportPadding) > window.innerWidth) {
- left = window.innerWidth - panelRect.width - viewportPadding;
- }
-
- left = Math.max(viewportPadding, left);
+ const left = Math.max(
+ viewportPadding,
+ (window.innerWidth - panelRect.width) / 2,
+ );
let top = triggerRect.bottom + 4;
const maxTop = window.innerHeight - panelRect.height - viewportPadding;
diff --git a/resources/views/components/forms/listbox.blade.php b/resources/views/components/forms/listbox.blade.php
index b61396a0d..a6078397c 100644
--- a/resources/views/components/forms/listbox.blade.php
+++ b/resources/views/components/forms/listbox.blade.php
@@ -14,7 +14,7 @@
'value' => null, // initial value when wire=false
'disabled' => false,
'tooltip' => true,
- 'portal' => false,
+ 'portal' => true,
'preserveValue' => false,
])
@@ -90,19 +90,26 @@
const gap = 4;
const edge = 12;
const triggerRect = trigger.getBoundingClientRect();
- const panelWidth = Math.max(triggerRect.width, panel.offsetWidth);
+ const panelWidth = Math.min(
+ Math.max(triggerRect.width, panel.offsetWidth),
+ window.innerWidth - (edge * 2),
+ );
const panelHeight = Math.min(panel.scrollHeight, 256);
const fitsBelow = window.innerHeight - triggerRect.bottom - gap >= panelHeight;
const top = fitsBelow
? triggerRect.bottom + gap
: Math.max(edge, triggerRect.top - gap - panelHeight);
- const left = Math.min(
- Math.max(edge, triggerRect.left),
- window.innerWidth - panelWidth - edge,
- );
+ const left = window.innerWidth < 768
+ ? (window.innerWidth - panelWidth) / 2
+ : Math.min(
+ Math.max(edge, triggerRect.left),
+ window.innerWidth - panelWidth - edge,
+ );
panel.style.top = `${top}px`;
panel.style.left = `${left}px`;
+ panel.style.width = `${panelWidth}px`;
+ panel.style.maxWidth = `${window.innerWidth - (edge * 2)}px`;
panel.style.minWidth = `${triggerRect.width}px`;
this.positioned = true;
}
@@ -123,7 +130,7 @@
@if ($portal)
false,
+ 'options' => [10, 25, 50, 100],
+ 'storageKey' => null,
+])
+
+
diff --git a/resources/views/components/shared-variables/editor.blade.php b/resources/views/components/shared-variables/editor.blade.php
index 15fcdb7eb..810b7f69c 100644
--- a/resources/views/components/shared-variables/editor.blade.php
+++ b/resources/views/components/shared-variables/editor.blade.php
@@ -54,15 +54,13 @@
-
-
+
@can('update', $resource)
diff --git a/resources/views/components/table-pagination.blade.php b/resources/views/components/table-pagination.blade.php
index df00fd7af..076fc8263 100644
--- a/resources/views/components/table-pagination.blade.php
+++ b/resources/views/components/table-pagination.blade.php
@@ -15,74 +15,43 @@
@php
$onFirstPage = (int) $currentPage <= 1;
$onLastPage = (int) $currentPage >= (int) $lastPage;
- $navButtonClass =
- 'flex w-10 items-center justify-center border-r border-neutral-200 text-neutral-500 transition-colors hover:bg-neutral-100 disabled:cursor-not-allowed disabled:opacity-35 dark:border-white/[0.10] dark:text-fg-dim dark:hover:bg-white/[0.06]';
- $lastNavButtonClass =
- 'flex w-10 items-center justify-center text-neutral-500 transition-colors hover:bg-neutral-100 disabled:cursor-not-allowed disabled:opacity-35 dark:text-fg-dim dark:hover:bg-white/[0.06]';
+ $buttonClass =
+ 'flex size-7 items-center justify-center rounded-md border border-neutral-200 text-neutral-500 transition-colors hover:bg-neutral-100 hover:text-black disabled:pointer-events-none disabled:opacity-35 dark:border-white/[0.08] dark:text-fg-dim dark:hover:bg-white/[0.06] dark:hover:text-fg';
$hasLoading = filled($wireTarget);
@endphp
-class('flex items-center justify-between gap-3 px-4 py-3') }}>
-
- Showing {{ $from }}–{{ $to }}
- of {{ $total }}
-
-
-
-
-
-
class('flex min-h-11 items-center justify-between border-t border-neutral-200 px-4 text-[11px] text-neutral-500 dark:border-white/[0.08] dark:text-fg-faint') }}>
+
+
{{ $from }}–{{ $to }} of {{ $total }}
+ @isset($pageSize)
+ {{ $pageSize }}
+ @endisset
+ @if ($hasLoading)
+
+
+ Loading page…
+
+ @endif
+
+
+
-
+
-
- @if ($hasLoading)
- {{ $currentPage }}
-
-
- Loading page…
-
- @else
- {{ $currentPage }}
- @endif
-
-
-
-
-
-
+
-
+
diff --git a/resources/views/components/table/dropdown.blade.php b/resources/views/components/table/dropdown.blade.php
new file mode 100644
index 000000000..110e0bde6
--- /dev/null
+++ b/resources/views/components/table/dropdown.blade.php
@@ -0,0 +1,68 @@
+@props([
+ 'panelClass' => '',
+ 'role' => 'listbox',
+ 'multiselectable' => false,
+])
+
+@php($panelId = 'table-dropdown-'.uniqid())
+
+
+
+ {{ $trigger }}
+
+
+
+
+ {{ $slot }}
+
+
+
diff --git a/resources/views/components/table/filter.blade.php b/resources/views/components/table/filter.blade.php
index b2385b995..25c6639b0 100644
--- a/resources/views/components/table/filter.blade.php
+++ b/resources/views/components/table/filter.blade.php
@@ -1,24 +1,25 @@
@props(['activeCount' => 0, 'activeText' => null, 'resetAction', 'resetLabel' => 'Reset filters'])
-
-
$activeCount > 0])>
-
- Filter
- @if ($activeCount > 0)
- {{ $activeCount }}
- @endif
-
-
+
+
+
+ $activeCount > 0])>
+
+ Filter
+ @if ($activeCount > 0)
+ {{ $activeCount }}
+ @endif
+
+
{{ $slot }}
+ wire:click="{{ $resetAction }}" @click="close()" @disabled($activeCount === 0)>
{{ $resetLabel }}
-
+
diff --git a/resources/views/components/table/sort.blade.php b/resources/views/components/table/sort.blade.php
index 46a54d566..7fcd4a975 100644
--- a/resources/views/components/table/sort.blade.php
+++ b/resources/views/components/table/sort.blade.php
@@ -1,10 +1,11 @@
-
-
-
- Sort
-
-
+
+
+
+
+
+ Sort
+
+
{{ $slot }}
-
+
diff --git a/resources/views/livewire/project/application/backup/index.blade.php b/resources/views/livewire/project/application/backup/index.blade.php
index 0401b4ede..a8fa6352d 100644
--- a/resources/views/livewire/project/application/backup/index.blade.php
+++ b/resources/views/livewire/project/application/backup/index.blade.php
@@ -111,20 +111,18 @@
-
-
+
+
Filter
-
-
+
+ x-on:click="typeFilter = option.value; close()">
-
-
+
-
-
+
+
Sort
-
-
+
+ x-on:click="sortBy = option.value; close()">
-
-
+
diff --git a/resources/views/livewire/project/application/deployment/index.blade.php b/resources/views/livewire/project/application/deployment/index.blade.php
index bc2a8bc70..20445e3c7 100644
--- a/resources/views/livewire/project/application/deployment/index.blade.php
+++ b/resources/views/livewire/project/application/deployment/index.blade.php
@@ -253,7 +253,13 @@
:current-page="$currentPage" :last-page="$lastPage"
wire-target="goToPage,previousPage,nextPage" first-action="goToPage(1)"
previous-action="previousPage" next-action="nextPage"
- last-action="goToPage({{ $lastPage }})" />
+ last-action="goToPage({{ $lastPage }})">
+ @unless ($embedded)
+
+
+
+ @endunless
+
@else
-
-
-
- Sort
-
-
+
+
+
+
+ Sort
+
+
+ x-on:click="sortBy = option.value; close(); page = 1">
-
-
+
@@ -152,31 +151,9 @@
-
-
+
-
-
+
-
-
+
+
Filter
-
-
+
Resource type
@@ -38,14 +33,13 @@
+ @click="resourceType = option.value; close()">
-
-
+
-
-
+
+
+
-
+
+
@@ -113,24 +114,23 @@
Clear filters
-
-
+
-
-
+
+
+
Sort
-
-
+
+
+ x-on:click="sortBy = option.value; close(); page = 1">
-
-
+
@@ -263,30 +262,9 @@
Try a different search or filter.
-
-
+
@@ -351,32 +329,10 @@
Try a different search or filter.
-
-
+
@endif
diff --git a/resources/views/livewire/project/service/volume-backup/index.blade.php b/resources/views/livewire/project/service/volume-backup/index.blade.php
index 7fd085a8b..b5bea7d96 100644
--- a/resources/views/livewire/project/service/volume-backup/index.blade.php
+++ b/resources/views/livewire/project/service/volume-backup/index.blade.php
@@ -143,20 +143,18 @@
-
-
+
+
Filter
-
-
+
+ x-on:click="typeFilter = option.value; close()">
-
-
+
-
-
+
+
Sort
-
-
+
+ x-on:click="sortBy = option.value; close()">
-
-
+
diff --git a/resources/views/livewire/project/shared/environment-variable/all.blade.php b/resources/views/livewire/project/shared/environment-variable/all.blade.php
index 6b68dde0a..923514efc 100644
--- a/resources/views/livewire/project/shared/environment-variable/all.blade.php
+++ b/resources/views/livewire/project/shared/environment-variable/all.blade.php
@@ -233,7 +233,11 @@
first-action="setEnvironmentVariablePage(1)"
previous-action="previousEnvironmentVariablePage"
next-action="nextEnvironmentVariablePage"
- last-action="setEnvironmentVariablePage({{ $lastPage }})" />
+ last-action="setEnvironmentVariablePage({{ $lastPage }})">
+
+
+
+
@else
diff --git a/resources/views/livewire/project/shared/get-logs.blade.php b/resources/views/livewire/project/shared/get-logs.blade.php
index f7ab19077..f96667b57 100644
--- a/resources/views/livewire/project/shared/get-logs.blade.php
+++ b/resources/views/livewire/project/shared/get-logs.blade.php
@@ -405,24 +405,16 @@
d="M9.53 16.122a3 3 0 0 0-5.78 1.128 2.25 2.25 0 0 1-2.4 2.245 4.5 4.5 0 0 0 8.4-2.245c0-.399-.078-.78-.22-1.128Zm0 0a15.998 15.998 0 0 0 3.388-1.62m-5.043-.025a15.994 15.994 0 0 1 1.622-3.395m3.42 3.42a15.995 15.995 0 0 0 4.764-4.648l3.876-5.814a1.151 1.151 0 0 0-1.597-1.597L14.146 6.32a15.996 15.996 0 0 0-4.649 4.763m3.42 3.42a6.776 6.776 0 0 0-3.42-3.42" />
-
-
+
+ class="runtime-log-icon-button" aria-haspopup="listbox" :aria-expanded="open">
-
-
-
+
diff --git a/resources/views/livewire/project/shared/storages/volume-backups/executions.blade.php b/resources/views/livewire/project/shared/storages/volume-backups/executions.blade.php
index e8fdbdab3..784843f6f 100644
--- a/resources/views/livewire/project/shared/storages/volume-backups/executions.blade.php
+++ b/resources/views/livewire/project/shared/storages/volume-backups/executions.blade.php
@@ -133,30 +133,14 @@
@endif
@endforeach
-
-
+
+
+
+
+
@else
-
-
+
+
+
Sort
-
-
+
+
+ x-on:click="sortBy = option.value; close(); page = 1">
-
-
+
@@ -166,31 +165,9 @@
-
-
+
-
-
+
-
-
- Showing
-
- of
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
@endif
diff --git a/resources/views/livewire/settings/scheduled-jobs.blade.php b/resources/views/livewire/settings/scheduled-jobs.blade.php
index c684a212e..838bb6da4 100644
--- a/resources/views/livewire/settings/scheduled-jobs.blade.php
+++ b/resources/views/livewire/settings/scheduled-jobs.blade.php
@@ -56,14 +56,11 @@
-
-
+
+
Filter
-
-
+
Type
@@ -71,7 +68,7 @@
@foreach (['all' => 'All types', 'backup' => 'Backups', 'task' => 'Tasks', 'cleanup' => 'Docker cleanup'] as $value => $label)
+ @click="close()">
{{ $label }}
@if ($filterType === $value)
✓
@@ -85,36 +82,31 @@
@foreach (['last_24h' => 'Last 24 hours', 'last_7d' => 'Last 7 days', 'last_30d' => 'Last 30 days', 'all' => 'All time'] as $value => $label)
+ @click="close()">
{{ $label }}
@if ($filterDate === $value)
✓
@endif
@endforeach
-
-
+
-
-
+
+
Sort
-
-
+
@foreach (['newest' => 'Newest first', 'oldest' => 'Oldest first'] as $value => $label)
+ @click="close()">
{{ $label }}
@if ($sortOrder === $value)
✓
@endif
@endforeach
-
-
+
@@ -191,26 +183,11 @@
@endforeach
-
-
- Showing of
- {{ $executions->count() }}
-
-
-
- Page of
-
-
-
-
-
-
-
-
-
+
@endif
@@ -260,26 +237,11 @@
@endforeach
-
-
- Showing of
- {{ $managerRuns->count() }}
-
-
-
- Page of
-
-
-
-
-
-
-
-
-
+
@endif
@@ -337,27 +299,12 @@
@endforeach
-
-
- {{ $skipTotalCount }} {{ Str::plural('skipped job', $skipTotalCount) }}
-
- @if ($skipTotalCount > $skipDefaultTake)
-
-
- Page {{ $skipCurrentPage }} of {{ ceil($skipTotalCount / $skipDefaultTake) }}
-
-
-
-
-
-
-
-
- @endif
-
+
@endif
diff --git a/resources/views/livewire/tags/show.blade.php b/resources/views/livewire/tags/show.blade.php
index 649a64bb9..1696382c0 100644
--- a/resources/views/livewire/tags/show.blade.php
+++ b/resources/views/livewire/tags/show.blade.php
@@ -42,8 +42,9 @@
-
-
+
+
+
Sort
-
-
+
+
+ x-on:click="sortBy = option.value; close(); page = 1">
-
-
+
@@ -122,29 +121,9 @@
-
-
+
-
-
+
+ last-action="setPage({{ $users->lastPage() }})">
+
+
+
+
@else
diff --git a/resources/views/livewire/team/member/index.blade.php b/resources/views/livewire/team/member/index.blade.php
index b2ad88710..687f870a3 100644
--- a/resources/views/livewire/team/member/index.blade.php
+++ b/resources/views/livewire/team/member/index.blade.php
@@ -129,58 +129,11 @@
description="Try a different name, email address, or role." />
-
-
- Showing
-
- of
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
@can('manageInvitations', currentTeam())
diff --git a/tests/Feature/ListboxTriggerTruncationTest.php b/tests/Feature/ListboxTriggerTruncationTest.php
index b4b503b9e..acbe900cf 100644
--- a/tests/Feature/ListboxTriggerTruncationTest.php
+++ b/tests/Feature/ListboxTriggerTruncationTest.php
@@ -39,6 +39,29 @@ test('listbox component uses shared trigger label truncation', function () {
->not->toContain('class="truncate" x-text="current"');
});
+test('portaled listboxes center in the mobile viewport', function () {
+ $html = Blade::render('');
+
+ expect($html)
+ ->toContain('window.innerWidth < 768')
+ ->toContain('(window.innerWidth - panelWidth) / 2')
+ ->toContain('panel.style.width = `${panelWidth}px`')
+ ->toContain('panel.style.maxWidth = `${window.innerWidth - (edge * 2)}px`')
+ ->toContain('x-show="open"')
+ ->not->toContain('x-show="open && positioned"');
+});
+
+test('legacy floating panels have a centered mobile fallback', function () {
+ $css = file_get_contents(resource_path('css/app.css'));
+
+ expect($css)
+ ->toContain('@media (max-width: 767px)')
+ ->toContain('.listbox-panel:not([style*="position: fixed"])')
+ ->toContain('position: fixed !important;')
+ ->toContain('left: 50% !important;')
+ ->toContain('transform: translate(-50%, -50%) !important;');
+});
+
test('searchable listbox component uses shared trigger label truncation', function () {
$html = Blade::render(<<<'BLADE'
toContain('table-toolbar')
->toContain('table-search')
->toContain('wire:model.live="search"')
+ ->toContain('x-teleport="body"')
+ ->toContain('positionPanel')
+ ->toContain('position: fixed')
+ ->toContain('floating-dropdown-panel')
+ ->toContain('window.innerWidth < 768')
+ ->toContain('(window.innerWidth - panelWidth) / 2')
+ ->toContain('panel.style.width = `${panelWidth}px`')
+ ->toContain('panel.style.maxWidth = `${window.innerWidth - (edge * 2)}px`')
+ ->toContain('x-show="open"')
+ ->not->toContain('x-show="open && positioned"')
->toContain('aria-multiselectable="true"')
->toContain('Reset filters')
->toContain('wire:click="clearFilters"')
@@ -61,3 +72,30 @@ it('uses the standard search control for frontend filtered infrastructure tables
->toContain('clear-when="search"')
->toContain("clear-action=\"search = ''\"");
});
+
+it('uses the collision aware dropdown on the projects page', function () {
+ $projects = file_get_contents(resource_path('views/livewire/project/index.blade.php'));
+
+ expect($projects)
+ ->toContain('not->toContain('x-show="sortOpen"');
+});
+
+it('uses collision aware filter and sort dropdowns on the resources page', function () {
+ $resources = file_get_contents(resource_path('views/livewire/project/resource/index.blade.php'));
+
+ expect(substr_count($resources, 'toBeGreaterThanOrEqual(2)
+ ->and($resources)
+ ->not->toContain('x-show="filterOpen"')
+ ->not->toContain('x-show="sortOpen"');
+});
+
+it('does not use legacy floating sort or filter panels', function () {
+ $views = collect(File::allFiles(resource_path('views')))
+ ->filter(fn (SplFileInfo $file): bool => $file->getExtension() === 'php')
+ ->map(fn (SplFileInfo $file): string => $file->getContents())
+ ->implode("\n");
+
+ expect($views)
+ ->not->toMatch('/x-show="(?:sortOpen|filterOpen|filtersOpen)"/');
+});
diff --git a/tests/Feature/TablePaginationLoadingTest.php b/tests/Feature/TablePaginationLoadingTest.php
index 207fd84ab..2b7a8a5fa 100644
--- a/tests/Feature/TablePaginationLoadingTest.php
+++ b/tests/Feature/TablePaginationLoadingTest.php
@@ -2,6 +2,47 @@
use Illuminate\Support\Facades\Blade;
+it('renders the shared page size selector', function () {
+ $html = Blade::render('');
+
+ expect($html)
+ ->toContain('aria-label="Items per page"')
+ ->toContain("\$wire.set('perPage'")
+ ->toContain('h-7!')
+ ->toContain('w-12!')
+ ->toContain('opacity-0')
+ ->toContain('selectedPageSize')
+ ->toContain('border-0')
+ ->toContain('text-[11px]!')
+ ->toContain('mb-0!')
+ ->toContain("localStorage.getItem('tests.page-size')")
+ ->toContain("localStorage.setItem('tests.page-size'")
+ ->toContain('value="10"')
+ ->toContain('value="25"')
+ ->toContain('value="50"')
+ ->toContain('value="100"');
+ expect($html)
+ ->toContain('value="custom"')
+ ->toContain('data-custom-page-size')
+ ->toContain('customOption?.remove()')
+ ->not->toContain('