matheusmarnt/scoutify
Scoutify adds a production-ready ⌘K/Ctrl+K global search modal to Laravel. Powered by Scout + Livewire, it searches across multiple Eloquent models, groups results by type, auto-discovers Searchable models, and stores recent searches in session.
Installation:
composer require matheusmarnt/scoutify
php artisan scoutify:install
Follow prompts to select Scout driver (Meilisearch, Algolia, Typesense, or Database).
Register Models:
php artisan scoutify:searchable
Select models to make globally searchable (or use --all flag). The command auto-edits model files.
Import Data:
php artisan scoutify:import
Add UI Components:
Place these in your layout (after $slot):
<x-scoutify::gs.trigger class="hidden lg:inline-flex" />
<x-scoutify::gs.trigger-mobile />
<livewire:scoutify::modal />
Trigger the search modal with ⌘K (Mac) or Ctrl+K (Windows/Linux). Type a query to see grouped results by model type (e.g., "Articles," "Users"). Click a result to navigate to its route.
Model Registration:
scoutify:searchable to auto-register models under app/Models/.globalSearchTitle(), globalSearchUrl()) for custom behavior.public function globalSearchTitle(): string { return $this->name; }
public function globalSearchUrl(): string { return route('users.show', $this); }
Query Customization:
globalSearchBuilder() for model-specific filters:
public function globalSearchBuilder(Builder $builder, string $query): Builder
{
return $builder->where('status', 'published');
}
Authorization:
HasGlobalSearchVisibility for fine-grained access control:
public function globalSearchVisibility(): VisibilityRule
{
return VisibilityRule::make()
->visibleToGuests()
->orWhenAuthenticated()
->policy('view')
->orPermission('edit-content');
}
File Previews:
HasGlobalSearchPreview to models with downloadable files:
public function globalSearchPreview(): ?PreviewDto
{
return PreviewDto::fromDisk('documents', $this->file_path);
}
scoutify:download events in JavaScript to handle downloads.Programmatic Triggers:
<button x-data @click="$dispatch('scoutify:open')">Search</button>
<button wire:click="$dispatchTo('scoutify::modal', 'scoutify:open')">Search</button>
config/scout.php for your chosen driver (e.g., Meilisearch, Algolia).ri-*, tabler-*) for custom icons:
composer require andreiio/blade-remix-icon
Use in models:
public static function globalSearchIcon(): string { return 'ri-customer-service-2-fill'; }
resources/lang/{locale}/scoutify.php.Modal Placement:
<livewire:scoutify::modal /> at the root layout level, outside conditionally rendered sections.Meilisearch Substring Search:
"ano" won’t match "Mariano".globalSearchBuilder() to configure attributesToSearchOn or switch to the database driver for LIKE-based search.Missing Scout Driver Packages:
scoutify:install may fail if driver packages aren’t installed.meilisearch/meilisearch-php) or let the installer handle it.Authorization Conflicts:
VisibilityRule logic may override global settings (secure/permissive).php artisan scoutify:test-visibility to debug visibility rules.File Preview Permissions:
HasGlobalSearchVisibility and the user passes the visibility check.Check Scout Index:
php artisan scout:flush
php artisan scout:import
Verify records are indexed with:
php artisan scout:search "test query"
Livewire Logs:
Enable Livewire logging in config/livewire.php:
'log' => env('LIVEWIRE_LOG', true),
Check storage/logs/livewire.log for modal initialization errors.
Visibility Testing:
Use the scoutify:test-visibility command to simulate user roles/permissions:
php artisan scoutify:test-visibility User --role=admin
Custom Theming: Override Tailwind classes via the fluent theme API:
Scoutify::theme()
->modalBackground('bg-gray-800')
->resultItemPadding('py-2 px-4');
Event Listeners: Extend functionality by listening to Scoutify events:
scoutify.searching: Triggered when a query is executed.scoutify.result.click: Fired when a user clicks a result.scoutify.download: Handle file downloads (see above).Dynamic Model Registration: Register models programmatically at runtime:
Scoutify::types()->register(Article::class);
Scoutify::types()->register(User::class);
Query Hooks: Modify search behavior globally via service providers:
Scoutify::query()->hook(function (Builder $builder, string $query) {
return $builder->where('deleted_at', null);
});
Icon Auto-Detection: Override the default icon prefix in a service provider:
Scoutify::types()->iconPrefix('tabler-');
Recent Searches: Persisted to session by default. Clear history via:
Scoutify::recent()->clear();
Or configure max items in config/scoutify.php:
'recent' => [
'max_items' => 10,
],
Dark Mode: Ensure your layout includes:
<html class="dark">
And Tailwind’s dark mode classes (e.g., dark:bg-gray-800).
Spatie Permissions:
Required for ->permission() and ->role() rules. Scoutify auto-detects the package but fails closed if missing. Install with:
composer require spatie/laravel-permission
How can I help you explore Laravel packages today?