diff --git a/resources/css/app.css b/resources/css/app.css
index 9115e00..569e7f8 100644
--- a/resources/css/app.css
+++ b/resources/css/app.css
@@ -243,6 +243,16 @@
block-size: 100%;
}
+/*
+ * resources/views/livewire/share-download.blade.php: a long file list scrolls on its own, as the
+ * upload page's does, so the download buttons stay near the top of the page. It is the page's main
+ * content, so it may take more of the window.
+ */
+.share-file-list {
+ max-block-size: min(32rem, 60dvh);
+ overflow-y: auto;
+}
+
/*
* resources/views/livewire/share-download.blade.php: the private text once the recipient shows it,
* as it was typed — its line breaks kept and a long word or key wrapped rather than overflowing.
diff --git a/resources/views/livewire/share-download.blade.php b/resources/views/livewire/share-download.blade.php
index fb2fdd6..fdc1909 100644
--- a/resources/views/livewire/share-download.blade.php
+++ b/resources/views/livewire/share-download.blade.php
@@ -94,25 +94,27 @@
})"
x-on:beforeunload.window="warnBeforeLeaving($event)"
>
-
- @foreach ($files as $file)
-
- {{ Number::fileSize($file->file_size) }}
-
-
-
-
-
-
-
-
-
- @endforeach
-
+
+
+ @foreach ($files as $file)
+
+ {{ Number::fileSize($file->file_size) }}
+
+
+
+
+
+
+
+
+
+ @endforeach
+
+
diff --git a/tests/Browser/ShareFlowTest.php b/tests/Browser/ShareFlowTest.php
index c2d7063..3e31a9e 100644
--- a/tests/Browser/ShareFlowTest.php
+++ b/tests/Browser/ShareFlowTest.php
@@ -297,3 +297,19 @@ test('Browse Folder picks a whole folder and keeps each file\'s path in it', fun
$page->assertSee('holiday/docs/notes.txt')
->assertNoJavaScriptErrors();
});
+
+test('a long file list scrolls on its own and keeps the download buttons on the first screen', function () {
+ $share = app(ShareService::class)->createShare(collect(range(1, 40))->map(fn (int $number): array => [
+ 'file' => UploadedFile::fake()->createWithContent("file-{$number}.txt", "file {$number}"),
+ 'relativePath' => null,
+ ])->all());
+
+ $page = ready(visit(route('share.download', $share, false))->resize(1280, 800));
+
+ $page->assertScript("(() => {
+ const list = document.querySelector('[data-test=share-file-list]');
+ return list.scrollHeight > list.clientHeight && getComputedStyle(list).overflowY === 'auto';
+ })()")
+ ->assertScript("[...document.querySelectorAll('[data-md-button]')].filter((button) => button.offsetParent !== null && button.textContent.trim().toLowerCase().startsWith('download all')).every((button) => button.getBoundingClientRect().bottom <= window.innerHeight)")
+ ->assertNoJavaScriptErrors();
+});