Liste sayfası
Panelin liste sayfalarının tamamı: araç çubuğu, filtre düğmesi, toplu seçim çubuğu, sıralanabilir tablo ve sayfalama. Görünüm Acun UI bileşenlerinden, davranış (arama, sıralama, seçim, sayfalama) WithListing trait'inden gelir.
Görünüm
Bir liste sayfasının parçaları: acun:list-toolbar (solda arama, sağda işlemler), acun:filter-button ile açılan Filtreler paneli, bir şey seçiliyken görünen acun:selection-bar, acun:sortable-th başlıklı tablo ve sayfalama çubuğu. Canlı örnekte Livewire olmadığı için tıklamalar sunucuya gitmez.
<div class="space-y-4">
<acun:list-toolbar>
<acun:search name="liste_arama" placeholder="Ürün adı veya stok kodu" />
<acun:slot:actions>
<acun:filter-button drawer="catalog-listing-filters" :count="2" />
<acun:button>Yeni Ürün</acun:button>
</acun:slot:actions>
</acun:list-toolbar>
<acun:selection-bar :count="2" clear-action="clearSelection">
<acun:button variant="white" size="sm">Aktifleştir</acun:button>
<acun:button variant="danger" size="sm">Sil</acun:button>
</acun:selection-bar>
<acun:table>
<table class="ui-table">
<thead>
<tr>
<th class="w-10"><acun:checkbox id="liste-tumu" aria-label="Tümünü seç" /></th>
<acun:sortable-th field="ad" sort-field="ad" sort-direction="asc">Ürün Adı</acun:sortable-th>
<acun:sortable-th field="stok_kodu" sort-field="ad" sort-direction="asc">Stok Kodu</acun:sortable-th>
<th class="text-center">Stok</th>
<th>Durum</th>
</tr>
</thead>
<tbody>
<tr><td><acun:checkbox id="liste-1" checked /></td><td class="font-medium text-gray-900 dark:text-zinc-100">Kablosuz kulaklık</td><td>WH-01</td><td class="text-center tabular-nums">312</td><td><acun:badge variant="success">Aktif</acun:badge></td></tr>
<tr><td><acun:checkbox id="liste-2" checked /></td><td class="font-medium text-gray-900 dark:text-zinc-100">Mekanik klavye</td><td>MK-04</td><td class="text-center tabular-nums">148</td><td><acun:badge variant="success">Aktif</acun:badge></td></tr>
<tr><td><acun:checkbox id="liste-3" /></td><td class="font-medium text-gray-900 dark:text-zinc-100">USB-C şarj aleti</td><td>UC-02</td><td class="text-center tabular-nums">96</td><td><acun:badge variant="danger">Pasif</acun:badge></td></tr>
</tbody>
</table>
</acun:table>
{{ $examplePaginator->links('acun-ui::components.ui.pagination') }}
</div>
<acun:drawer name="catalog-listing-filters" docked title="Filtreler" compact>
<acun:select name="liste_durum" :options="['' => 'Tüm Durumlar', '1' => 'Aktif', '0' => 'Pasif']" />
</acun:drawer>
| Prop | Değerler |
|---|---|
acun:list-toolbar | Varsayılan slot: arama · actions slot'u: sağdaki düğmeler |
acun:filter-button | drawer: açılacak çekmecenin adı · count: etkin filtre sayısı · label: metin (varsayılan Filtreler) |
acun:selection-bar | count · all-matching · total · clear-action |
Livewire bileşeni
Bileşene WithListing ekleyin ve iki soyut metodu yazın: defaultSortField() varsayılan sıralama alanını, currentPageKeys() görünen sayfanın satır anahtarlarını döndürür. Varsayılan dışındaki sıralama alanlarını sortableFields() ile açın; listede olmayan alanlar sortBy() ve URL tarafından yok sayılır. with() metodunun başında fillPageSelection() çağırın.
use Acun\Ui\Livewire\Concerns\WithListing;
use Acun\Ui\Search\SearchField;
use Acun\Ui\Search\SearchMode;
new class extends Component
{
use WithListing;
public string $durum = '';
protected function defaultSortField(): string
{
return 'ad';
}
protected function sortableFields(): array
{
return ['ad', 'stok_kodu'];
}
protected function currentPageKeys(): array
{
return $this->sorgu()->forPage($this->getPage(), $this->perPage)->pluck('id')->all();
}
public function updatedDurum(): void
{
$this->resetPage();
$this->clearSelection();
}
// Ürün adında içinde geçen sözcük, stok kodunda baştan (ad_search, stok_kodu_search kolonları).
protected function searchFields(): array
{
return [SearchField::make('ad', SearchMode::Contains), SearchField::make('stok_kodu')];
}
private function sorgu(): Builder
{
return $this->applySearch(Urun::query())
->when($this->durum !== '', fn ($q) => $q->where('aktif_mi', $this->durum))
->orderBy($this->sortField, $this->sortDirection);
}
public function with(): array
{
$this->fillPageSelection();
return ['urunler' => $this->sorgu()->paginate($this->perPage)];
}
};
| Prop | Değerler |
|---|---|
defaultSortField() | Zorunlu: varsayılan sıralama alanı |
currentPageKeys() | Zorunlu: görünen sayfanın satır anahtarları |
sortableFields() | Sıralanabilir alanlar (varsayılan: yalnızca defaultSortField) |
perPageOptions() | Sayfa boyutları (varsayılan: 10 | 25 | 50 | 100) |
Blade şablonu
Görünümdeki parçaları trait'in özelliklerine bağlayın: arama search, başlık kutusu pageSelected, satır kutuları selected. acun:sortable-th tıklanınca sortBy() çağırır. Sayfalama için links() yeterlidir; trait görünüm olarak Acun UI sayfalamasını seçer.
<acun:list-toolbar>
<acun:search wire:model.live.debounce.400ms="search" placeholder="Ürün adı veya stok kodu" />
<acun:slot:actions>
<acun:filter-button drawer="urun-filtreler" :count="$durum !== '' ? 1 : 0" />
</acun:slot:actions>
</acun:list-toolbar>
<acun:selection-bar :count="count($selected)" :all-matching="$allMatchingSelected" :total="$urunler->total()">
<acun:modal.trigger name="urun-toplu-sil"><acun:button variant="danger" size="sm">Sil</acun:button></acun:modal.trigger>
</acun:selection-bar>
<acun:table>
<table class="ui-table">
<thead>
<tr>
<th class="w-10"><acun:checkbox wire:model.live="pageSelected" aria-label="Sayfadakilerin tümünü seç" /></th>
<acun:sortable-th field="ad" :sort-field="$sortField" :sort-direction="$sortDirection">Ürün Adı</acun:sortable-th>
<acun:sortable-th field="stok_kodu" :sort-field="$sortField" :sort-direction="$sortDirection">Stok Kodu</acun:sortable-th>
</tr>
</thead>
<tbody>
@foreach ($urunler as $urun)
<tr wire:key="urun-{{ $urun->id }}">
<td><acun:checkbox wire:model.live="selected" value="{{ $urun->id }}" /></td>
<td>{{ $urun->ad }}</td>
<td>{{ $urun->stok_kodu }}</td>
</tr>
@endforeach
</tbody>
</table>
</acun:table>
{{ $urunler->links() }}
Filtreye uyan tümünü seçmek
Başlık kutusu işaretlenince görünen sayfanın anahtarları seçilir ve allMatchingSelected açılır; acun:selection-bar bu durumda total değerini "filtreye uyan tümü" olarak gösterir. Kullanıcı bir satırın işaretini kaldırırsa bu mod kendiliğinden kapanır ve seçim yalnızca işaretli satırlara iner. Arama değiştiğinde seçim temizlenir; kendi filtrelerinizde clearSelection() çağırmayı unutmayın.
<acun:selection-bar :count="25" :all-matching="true" :total="148" clear-action="clearSelection">
<acun:button variant="white" size="sm">Pasifleştir</acun:button>
</acun:selection-bar>
| Prop | Değerler |
|---|---|
all-matching | true | false |
total | Filtreye uyan toplam kayıt |
clear-action | Seçimi temizleyen Livewire metodu (varsayılan clearSelection; null ise düğme gizlenir) |
Arama kolonları
Arama, veritabanının kaynak kolondan ürettiği normalize edilmiş bir kolonda çalışır. Türkçe karakter ve büyük/küçük harf farkı yoktur: "ayse" Ayşe'yi, "ismail isik" İsmail Işık'ı bulur. Kolonu migration'da searchColumn() ile ekleyin; ayrı kolonlardaki ad ve soyad tek bir kolonda birleşebilir. Varsayılan mod baştan aramadır ve indeksi kullanır; Contains bütün satırları okur. Terimdeki % ve _ düz metin sayılır. Ayrıntılar: Arama kılavuzu.
// Migration
Schema::table('musteriler', function (Blueprint $table) {
$table->searchColumn('vergi_no'); // vergi_no_search + indeks
$table->searchColumn(['ad', 'soyad'], 'ad_soyad_search'); // "Ayşe Yılmaz" birleşik aranır
});
// Bileşen
protected function searchFields(): array
{
return [
SearchField::make('vergi_no', SearchMode::Exact),
SearchField::column('ad_soyad_search', SearchMode::Contains),
];
}
| Prop | Değerler |
|---|---|
SearchMode | Prefix (varsayılan, indeksli) | Exact | Contains (tarama) | FullText (MySQL FULLTEXT) |
SearchField::make(kaynak, mod, kolon) | kaynak_search kolonu; birleştirilmiş tabloda users.email gibi nitelenir |
SearchField::column(kolon, mod) | Birden çok kaynaktan üretilmiş kolon |
Prop'lar ve slot'lar
Bileşenin kabul ettiği değerler.
| Prop | Varsayılan | Açıklama |
|---|---|---|
$search | '' | Arama terimi · URL: ?q= · değişince sayfa başa döner, seçim temizlenir |
$sortField | '' | URL: ?sort= · izin verilmeyen değer defaultSortField() olur |
$sortDirection | asc | asc · desc · URL: ?direction= |
$perPage | 25 | perPageOptions() dışındaki değer ilk seçeneğe döner |
$selected | [] | Seçili satır anahtarları (wire:model.live="selected") |
$pageSelected | false | Başlık kutusu; true olunca currentPageKeys() seçilir |
$allMatchingSelected | false | Filtreye uyan tümü seçili; bir satırın işareti kalkınca false olur |
defaultSortField() | — | Zorunlu (abstract) |
currentPageKeys() | — | Zorunlu (abstract) |
sortableFields() | [defaultSortField()] | Sıralanabilir alanlar |
perPageOptions() | [10, 25, 50, 100] | İzin verilen sayfa boyutları |
sortBy($field) | — | Aynı alanda yönü çevirir, yeni alanda asc başlar; sayfayı başa alır |
clearSelection() | — | selected, pageSelected ve allMatchingSelected değerlerini sıfırlar |
fillPageSelection() | — | with() başında çağrılır; "tümü seçili" iken yeni sayfanın anahtarlarını ekler |
applySearch($q, $terim = null, $alanlar = null) | — | $search ile searchFields() alanlarında arar; Türkçe karakter ve büyük/küçük harf duyarsız |
searchFields() | — | Arama alanları (SearchField listesi) |
paginationView() | acun-ui::components.ui.pagination | links() bu görünümü kullanır |