108 lines
3.1 KiB
PHP
108 lines
3.1 KiB
PHP
|
|
<?php
|
|||
|
|
|
|||
|
|
namespace App\Livewire;
|
|||
|
|
|
|||
|
|
use App\Models\Document;
|
|||
|
|
use App\Services\DocumentService;
|
|||
|
|
use Livewire\Component;
|
|||
|
|
use Livewire\Attributes\Computed;
|
|||
|
|
|
|||
|
|
class QuickSwitcher extends Component
|
|||
|
|
{
|
|||
|
|
public $search = '';
|
|||
|
|
public $selectedIndex = 0;
|
|||
|
|
|
|||
|
|
#[Computed]
|
|||
|
|
public function results()
|
|||
|
|
{
|
|||
|
|
if (empty($this->search)) {
|
|||
|
|
return Document::select('id', 'title', 'slug', 'path', 'updated_at')
|
|||
|
|
->orderBy('updated_at', 'desc')
|
|||
|
|
->limit(10)
|
|||
|
|
->get()
|
|||
|
|
->map(fn($doc) => [
|
|||
|
|
'id' => $doc->id,
|
|||
|
|
'title' => $doc->title,
|
|||
|
|
'slug' => $doc->slug,
|
|||
|
|
'directory' => dirname($doc->path),
|
|||
|
|
])
|
|||
|
|
->toArray();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// FULLTEXT検索を使用(日本語対応)
|
|||
|
|
$results = Document::select('id', 'title', 'slug', 'path', 'updated_at')
|
|||
|
|
->whereRaw('MATCH(title, content) AGAINST(? IN BOOLEAN MODE)', [$this->search])
|
|||
|
|
->orderBy('updated_at', 'desc')
|
|||
|
|
->limit(10)
|
|||
|
|
->get()
|
|||
|
|
->map(fn($doc) => [
|
|||
|
|
'id' => $doc->id,
|
|||
|
|
'title' => $doc->title,
|
|||
|
|
'slug' => $doc->slug,
|
|||
|
|
'directory' => dirname($doc->path),
|
|||
|
|
])
|
|||
|
|
->toArray();
|
|||
|
|
|
|||
|
|
// FULLTEXT検索で結果がない場合は LIKE 検索にフォールバック
|
|||
|
|
if (empty($results)) {
|
|||
|
|
$results = Document::select('id', 'title', 'slug', 'path', 'updated_at')
|
|||
|
|
->where(function($query) {
|
|||
|
|
$query->where('title', 'like', '%' . $this->search . '%')
|
|||
|
|
->orWhere('content', 'like', '%' . $this->search . '%');
|
|||
|
|
})
|
|||
|
|
->orderBy('updated_at', 'desc')
|
|||
|
|
->limit(10)
|
|||
|
|
->get()
|
|||
|
|
->map(fn($doc) => [
|
|||
|
|
'id' => $doc->id,
|
|||
|
|
'title' => $doc->title,
|
|||
|
|
'slug' => $doc->slug,
|
|||
|
|
'directory' => dirname($doc->path),
|
|||
|
|
])
|
|||
|
|
->toArray();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return $results;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public function updated($propertyName)
|
|||
|
|
{
|
|||
|
|
if ($propertyName === 'search') {
|
|||
|
|
$this->selectedIndex = 0;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public function selectNext()
|
|||
|
|
{
|
|||
|
|
$results = $this->results;
|
|||
|
|
if ($this->selectedIndex < count($results) - 1) {
|
|||
|
|
$this->selectedIndex++;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public function selectPrevious()
|
|||
|
|
{
|
|||
|
|
if ($this->selectedIndex > 0) {
|
|||
|
|
$this->selectedIndex--;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public function selectDocument()
|
|||
|
|
{
|
|||
|
|
$results = $this->results;
|
|||
|
|
if (isset($results[$this->selectedIndex])) {
|
|||
|
|
$document = $results[$this->selectedIndex];
|
|||
|
|
|
|||
|
|
// id が存在することを確認
|
|||
|
|
if (!empty($document['id'])) {
|
|||
|
|
return $this->redirect(route('documents.show', $document['id']));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public function render()
|
|||
|
|
{
|
|||
|
|
return view('livewire.quick-switcher');
|
|||
|
|
}
|
|||
|
|
}
|