File Preview & Download
Any model can expose an inline file preview pane inside the search modal. Implement HasGlobalSearchPreview and return a PreviewDto — Scoutify handles the rest.
Basic setup
Section titled “Basic setup”use Matheusmarnt\Scoutify\Contracts\HasGlobalSearchPreview;use Matheusmarnt\Scoutify\Support\PreviewDto;
class Document extends Model implements GloballySearchable, HasGlobalSearchPreview{ use Searchable;
public function globalSearchPreview(): ?PreviewDto { return PreviewDto::fromDisk( disk: 'documents', path: $this->file_path, ); }}Return null to suppress the preview pane for a specific record (e.g. when no file is attached).
Storage-based vs. external URL
Section titled “Storage-based vs. external URL”Use PreviewDto::fromDisk() when the file lives on a Laravel filesystem disk:
PreviewDto::fromDisk( disk: 'documents', // any disk defined in config/filesystems.php path: $this->file_path, // path relative to the disk root mime: 'application/pdf', // optional — auto-detected from disk if omitted filename: $this->name, // optional — defaults to basename($path) sizeBytes: $this->size, // optional ttl: 3600, // optional — signed URL TTL in seconds (default 3600))URL resolution order:
- If the disk supports temporary URLs (e.g. S3), Scoutify generates a pre-signed URL directly.
- Otherwise, Scoutify streams the file through a signed
scoutify.preview.streamroute — no extra config needed.
Use PreviewDto::fromUrl() when the file is already publicly accessible:
PreviewDto::fromUrl( url: 'https://cdn.example.com/reports/q1.pdf', mime: 'application/pdf', // optional filename: 'Q1 Report', // optional — defaults to basename of URL path)External URLs are passed directly to the viewer. No signed route, no streaming.
Viewer selection
Section titled “Viewer selection”Scoutify picks the viewer automatically based on the resolved MIME type:
| MIME | Viewer |
|---|---|
application/pdf | Native PDF embed |
image/* | Inline image |
video/* | HTML5 video player |
| Anything else | Fallback — external link and download button |
MIME resolution order:
- Explicit
mimeon thePreviewDto - Auto-detected from the disk (
mimeType()) — storage-based files only - Falls back to
application/octet-stream
Download
Section titled “Download”When the user clicks the download button, Scoutify dispatches a scoutify:download browser event. Add a listener to your root layout to trigger the browser’s native download:
window.addEventListener('scoutify:download', (e) => { const a = document.createElement('a'); a.href = e.detail.url; a.download = e.detail.filename ?? ''; document.body.appendChild(a); a.click(); a.remove();});The scoutify:download event carries { url: string, filename: string } in its detail.
Authorization
Section titled “Authorization”Preview and download reuse the same authorization rules as search results. A user who cannot see a record in search results cannot stream or download its file either — GlobalSearchAuthorizer is checked at the stream route level before serving any content.
No additional policy configuration is needed.
Keyboard
Section titled “Keyboard”Results list
Section titled “Results list”| Key | Action |
|---|---|
Tab | Moves focus from the search input to the Preview button on the active row. A second Tab moves to the Download button. A third Tab returns focus to the search input. |
Shift+Tab | Reverses the focus cycle: input ← Download ← Preview. |
Enter | When focus is on a Preview or Download button, activates the button — does not navigate to the record’s route. |
↑ / ↓ | Navigate between rows. If an action button is focused, focus returns to the input first. |
Preview pane
Section titled “Preview pane”| Key | Action |
|---|---|
Esc | Closes the preview pane and returns to the results list. A second Esc dismisses the modal entirely. |
Enter | When focus is on the Back button (auto-focused when the preview opens), closes the preview. |
Tab | Cycles through the Back button and the download link in the preview header. |
↑ ↓ PageDown PageUp | Not intercepted — the browser forwards them to the embedded PDF or video viewer. |
Custom viewer
Section titled “Custom viewer”Override the viewer Blade view for a specific record by setting the view parameter:
PreviewDto::fromDisk( disk: 'documents', path: $this->file_path, view: 'my-package::preview.custom',)The custom view receives $dto (PreviewDto) and $url (resolved stream/temporary URL) as variables.