Initial commit
This commit is contained in:
249
resources/views/livewire/datatables/datatable.blade.php
Normal file
249
resources/views/livewire/datatables/datatable.blade.php
Normal file
@@ -0,0 +1,249 @@
|
||||
<div my-6>
|
||||
@if($beforeTableSlot)
|
||||
<div class="mt-8">
|
||||
@include($beforeTableSlot)
|
||||
</div>
|
||||
@endif
|
||||
<div class="relative">
|
||||
<div class="flex items-center justify-between my-6">
|
||||
<div class="flex items-center h-10">
|
||||
@if($this->searchableColumns()->count())
|
||||
<div class="flex rounded-lg w-96 shadow-sm">
|
||||
<div class="relative flex-grow focus-within:z-10">
|
||||
<div class="absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none">
|
||||
<svg class="w-5 h-5 text-theme-muted" viewBox="0 0 20 20" stroke="currentColor" fill="none">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
|
||||
</svg>
|
||||
</div>
|
||||
<input wire:model.live.debounce.500ms="search" class="block w-full py-3 pl-10 text-sm border-theme-border leading-4 rounded-md shadow-sm focus:border-primary-300 focus:ring focus:ring-primary-200 focus:ring-opacity-50 focus:outline-none" placeholder="{{__('Search in')}} {{ $this->searchableColumns()->map->label->join(', ') }}" type="text" />
|
||||
<div class="absolute inset-y-0 right-0 flex items-center pr-2">
|
||||
<button wire:click="$set('search', null)" class="text-theme-muted hover:text-red-600 focus:outline-none">
|
||||
<x-icons.x-circle class="w-5 h-5 stroke-current" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
@if($this->activeFilters)
|
||||
<span class="text-xl text-theme-muted uppercase">{{ __('Fileters Active') }}</span>
|
||||
@endif
|
||||
|
||||
<div class="flex flex-wrap items-center space-x-1">
|
||||
<x-icons.cog wire:loading class="text-theme-muted h-9 w-9 animate-spin" />
|
||||
|
||||
@if($this->activeFilters)
|
||||
<button wire:click="clearAllFilters" class="flex items-center px-3 text-xs font-medium tracking-wider text-red-500 uppercase bg-white border border-red-400 space-x-2 rounded-md leading-4 hover:bg-red-200 focus:outline-none"><span>{{ __('Reset') }}</span>
|
||||
<x-icons.x-circle class="m-2" />
|
||||
</button>
|
||||
@endif
|
||||
|
||||
@if(count($this->massActionsOptions))
|
||||
<div class="flex items-center justify-center space-x-1">
|
||||
<label for="datatables_mass_actions">{{ __('With selected') }}:</label>
|
||||
<select wire:model.live="massActionOption" class="px-3 text-xs font-medium tracking-wider uppercase bg-white border border-green-400 space-x-2 rounded-md leading-4 focus:outline-none" id="datatables_mass_actions">
|
||||
<option value="">{{ __('Choose...') }}</option>
|
||||
@foreach($this->massActionsOptions as $group => $items)
|
||||
@if(!$group)
|
||||
@foreach($items as $item)
|
||||
<option value="{{$item['value']}}">{{$item['label']}}</option>
|
||||
@endforeach
|
||||
@else
|
||||
<optgroup label="{{$group}}">
|
||||
@foreach($items as $item)
|
||||
<option value="{{$item['value']}}">{{$item['label']}}</option>
|
||||
@endforeach
|
||||
</optgroup>
|
||||
@endif
|
||||
@endforeach
|
||||
</select>
|
||||
<button
|
||||
wire:click="massActionOptionHandler"
|
||||
class="flex items-center px-4 py-2 text-xs font-medium tracking-wider text-green-500 uppercase bg-white border border-green-400 rounded-md leading-4 hover:bg-green-200 focus:outline-none" type="submit" title="Submit"
|
||||
>Go</button>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if($exportable)
|
||||
<div x-data="{ init() {
|
||||
window.livewire.on('startDownload', link => window.open(link, '_blank'))
|
||||
} }" x-init="init">
|
||||
<button wire:click="export" class="flex items-center px-3 text-xs font-medium tracking-wider text-theme-secondary uppercase bg-white border border-theme-secondary space-x-2 rounded-md leading-4 hover:text-theme-muted focus:outline-none"><span>{{ __('Export') }}</span>
|
||||
<x-icons.excel class="m-2" /></button>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if($hideable === 'select')
|
||||
@include('datatables::hide-column-multiselect')
|
||||
@endif
|
||||
|
||||
@foreach ($columnGroups as $name => $group)
|
||||
<button wire:click="toggleGroup('{{ $name }}')"
|
||||
class="px-3 py-2 text-xs font-medium tracking-wider text-green-500 uppercase bg-white border border-green-400 rounded-md leading-4 hover:bg-green-200 focus:outline-none">
|
||||
<span class="flex items-center h-5">{{ isset($this->groupLabels[$name]) ? __($this->groupLabels[$name]) : __('Toggle :group', ['group' => $name]) }}</span>
|
||||
</button>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if($hideable === 'buttons')
|
||||
<div class="p-2 grid grid-cols-8 gap-2">
|
||||
@foreach($this->columns as $index => $column)
|
||||
@if ($column['hideable'])
|
||||
<button wire:click="toggle('{{ $index }}')" class="px-3 py-2 rounded text-white text-xs focus:outline-none
|
||||
{{ $column['hidden'] ? 'bg-blue-100 hover:bg-blue-300 text-black' : 'bg-blue-500 hover:bg-blue-800' }}">
|
||||
{{ $column['label'] }}
|
||||
</button>
|
||||
@endif
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div wire:loading.class="opacity-50" class="rounded-sm @unless($complex || $this->hidePagination) rounded-sm @endunless shadow-sm bg-white max-w-screen overflow-x-scroll @if($this->activeFilters) border-blue-500 @else border-gray-100 border-b-2 rounded-sm @endif @if($complex) @endif">
|
||||
<div>
|
||||
<div class="table min-w-full align-middle">
|
||||
@unless($this->hideHeader)
|
||||
<div class="table-row divide-x divide-gray-200 bg-theme-primary">
|
||||
@foreach($this->columns as $index => $column)
|
||||
@if($hideable === 'inline')
|
||||
@include('datatables::header-inline-hide', ['column' => $column, 'sort' => $sort])
|
||||
@elseif($column['type'] === 'checkbox')
|
||||
@unless($column['hidden'])
|
||||
<div class="flex justify-center table-cell w-32 h-12 px-6 py-4 overflow-hidden text-xs font-medium tracking-wider text-left text-theme-primary uppercase align-top border-gray-100 bg-gray-50 leading-4 focus:outline-none">
|
||||
<div class="px-3 py-1 rounded @if(count($selected)) bg-orange-400 @else bg-theme-primary text-white @endif text-white text-center">
|
||||
{{ count($selected) }}
|
||||
</div>
|
||||
</div>
|
||||
@endunless
|
||||
@else
|
||||
@include('datatables::header-no-hide', ['column' => $column, 'sort' => $sort])
|
||||
@endif
|
||||
@endforeach
|
||||
</div>
|
||||
@endunless
|
||||
<div class="table-row bg-blue-100 divide-x divide-blue-200">
|
||||
@foreach($this->columns as $index => $column)
|
||||
@if($column['hidden'])
|
||||
@if($hideable === 'inline')
|
||||
<div class="table-cell w-5 overflow-hidden align-top bg-blue-100"></div>
|
||||
@endif
|
||||
@elseif($column['type'] === 'checkbox')
|
||||
@include('datatables::filters.checkbox')
|
||||
@elseif($column['type'] === 'label')
|
||||
<div class="table-cell overflow-hidden align-top">
|
||||
{{ $column['label'] ?? '' }}
|
||||
</div>
|
||||
@else
|
||||
<div class="table-cell overflow-hidden align-top">
|
||||
@isset($column['filterable'])
|
||||
@if( is_iterable($column['filterable']) )
|
||||
<div wire:key="{{ $index }}">
|
||||
@include('datatables::filters.select', ['index' => $index, 'name' => $column['label'], 'options' => $column['filterable']])
|
||||
</div>
|
||||
@else
|
||||
<div wire:key="{{ $index }}">
|
||||
@include('datatables::filters.' . ($column['filterView'] ?? $column['type']), ['index' => $index, 'name' => $column['label']])
|
||||
</div>
|
||||
@endif
|
||||
@endisset
|
||||
</div>
|
||||
@endif
|
||||
@endforeach
|
||||
</div>
|
||||
@forelse($this->results as $row)
|
||||
<div class="table-row p-1 {{ $this->rowClasses($row, $loop) }}">
|
||||
@foreach($this->columns as $column)
|
||||
@if($column['hidden'])
|
||||
@if($hideable === 'inline')
|
||||
<div class="table-cell w-5 overflow-hidden align-top"></div>
|
||||
@endif
|
||||
@elseif($column['type'] === 'checkbox')
|
||||
@include('datatables::checkbox', ['value' => $row->checkbox_attribute])
|
||||
@elseif($column['type'] === 'label')
|
||||
@include('datatables::label')
|
||||
@else
|
||||
<div class="table-cell px-6 py-2 whitespace-no-wrap @if($column['align'] === 'right') text-right @elseif($column['align'] === 'center') text-center @else text-left @endif {{ $this->cellClasses($row, $column) }}">
|
||||
@if(($column['type'] ?? '') === 'html' || ($column['allow_html'] ?? false))
|
||||
{{-- XSS WARNING: HTML rendering allowed for this column. Ensure data is sanitized! --}}
|
||||
{!! $row->{$column['name']} !!}
|
||||
@else
|
||||
{{-- Default: Escape output for XSS protection --}}
|
||||
{{ $row->{$column['name']} }}
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
@endforeach
|
||||
</div>
|
||||
@empty
|
||||
<p class="p-3 text-lg text-theme-primary">
|
||||
{{ __("There's Nothing to show at the moment") }}
|
||||
</p>
|
||||
@endforelse
|
||||
|
||||
@if ($this->hasSummaryRow())
|
||||
<div class="table-row p-1">
|
||||
@foreach($this->columns as $column)
|
||||
@unless($column['hidden'])
|
||||
@if ($column['summary'])
|
||||
<div class="table-cell px-6 py-2 whitespace-no-wrap @if($column['align'] === 'right') text-right @elseif($column['align'] === 'center') text-center @else text-left @endif {{ $this->cellClasses($row, $column) }}">
|
||||
{{ $this->summarize($column['name']) }}
|
||||
</div>
|
||||
@else
|
||||
<div class="table-cell"></div>
|
||||
@endif
|
||||
@endunless
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@unless($this->hidePagination)
|
||||
<div class="max-w-screen bg-white @unless($complex) @endunless border-2 @if($this->activeFilters) border-blue-500 @else border-transparent @endif">
|
||||
<div class="items-center justify-between p-2 sm:flex">
|
||||
{{-- check if there is any data --}}
|
||||
@if(count($this->results))
|
||||
<div class="flex items-center my-2 sm:my-0">
|
||||
<select name="perPage" class="block w-full py-2 pl-3 pr-10 mt-1 text-base border-theme-border form-select leading-6 focus:outline-none focus:ring focus:ring-primary-200 focus:ring-opacity-50 focus:border-primary-300 sm:text-sm sm:leading-5" wire:model.live="perPage">
|
||||
@foreach(config('livewire-datatables.per_page_options', [ 10, 25, 50, 100 ]) as $per_page_option)
|
||||
<option value="{{ $per_page_option }}">{{ $per_page_option }}</option>
|
||||
@endforeach
|
||||
<option value="99999999">{{__('All')}}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="my-4 sm:my-0">
|
||||
<div class="lg:hidden">
|
||||
<span class="space-x-2">{{ $this->results->links('datatables::tailwind-simple-pagination') }}</span>
|
||||
</div>
|
||||
|
||||
<div class="justify-center hidden lg:flex">
|
||||
<span>{{ $this->results->links('datatables::tailwind-pagination') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-end text-theme-secondary">
|
||||
{{__('Results')}} {{ $this->results->firstItem() }} - {{ $this->results->lastItem() }} {{__('of')}}
|
||||
{{ $this->results->total() }}
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
@if($complex)
|
||||
<div class="bg-gray-50 px-4 py-4 rounded-b-lg rounded-t-none shadow-sm border-4 @if($this->activeFilters) border-blue-500 @else border-transparent @endif @if($complex) border-t-0 @endif">
|
||||
<livewire:complex-query :columns="$this->complexColumns" :persistKey="$this->persistKey" :savedQueries="method_exists($this, 'getSavedQueries') ? $this->getSavedQueries() : null" />
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if($afterTableSlot)
|
||||
<div class="mt-8">
|
||||
@include($afterTableSlot)
|
||||
</div>
|
||||
@endif
|
||||
<span class="hidden text-sm text-left text-center text-right text-theme-primary bg-gray-100 bg-yellow-100 leading-5 bg-gray-50"></span>
|
||||
</div>
|
||||
Reference in New Issue
Block a user