gorlabs/tailwind-datatables
Laravel package that integrates Yajra DataTables with a Tailwind CSS + Alpine.js UI. Supports server-side processing, search, pagination, sorting, buttons, and rich column customization. Publish config and optional CSS assets for easy theming.
Bu kılavuz, mevcut bir Laravel Breeze (Livewire + Blade stack) projesine gorlabs/tailwind-datatables Composer paketini adım adım nasıl entegre edeceğinizi anlatmaktadır. Kılavuz, Tailwind CSS v3.x uyumluluğunu sağlamak için kritik notlar içermektedir.
Ön Gereksinimler PHP 8.2 veya üzeri
Composer
Node.js ve npm/Yarn
Laravel 12.x
Adım 1: Proje Oluşturma (Laravel Breeze) Lütfen proje geliştrimeye datatable ile oluşturacağınız bu proje ile başlayın çünkü bir çok sorunu çözmüş olarak başlaycaksınız
Yeni Laravel Projesi Oluştur:
laravel new livewire-example && cd livewire-example && touch resources/js/bootstrap.js && composer require laravel/breeze --dev && php artisan breeze:install livewire
Gelen seçeneklerden Livewire seçerek devam edin Laravel's built-in authentication seçin
Would you like to use Laravel Volt? istediğinizi seçin sonra Pest yadaPJPUnit seçin devam edin Would you like to run npm install and npm run build? istediğinizi seçin
Kurulum sorunsuzca tamamlandıysa .env dosyasındaki veritabanı seçeneklerini düzenleyin Veritabanınızı Hazırlayın: .env dosyanızda veritabanı bağlantı ayarlarını yapın (örn. DB_DATABASE=gorlabs_datatable).
Adım 2: gorlabs/tailwind-datatables Paketini Kurma
composer require gorlabs/tailwind-datatables
Paketin Asset ve Konfigürasyonlarını Yayınla: Bu komut, paketin CSS/JS varlıklarını ve konfigürasyon dosyalarını projenizin içine kopyalar.
php artisan vendor:publish --tag=tailwind-datatables-views
php artisan vendor:publish --tag=gorlabs-tailwind-datatables-config
php artisan vendor:publish --tag=tailwind-datatables-css
gorlabs-datatable/tailwind.config.js dosyanızı açın.
Dosyanın içeriğini aşağıdaki gibi tamamen değiştirin. Bu, Tailwind Forms pluginini doğru şekilde import edecek ve özel renkleri tanımlayacaktır.
import defaultTheme from 'tailwindcss/defaultTheme';
import forms from '[@tailwindcss](https://github.com/tailwindcss)/forms';
/** [@type](https://github.com/type) {import('tailwindcss').Config} */
export default {
content: [
'./vendor/laravel/framework/src/Illuminate/Pagination/resources/views/*.blade.php',
'./storage/framework/views/*.php',
'./resources/views/**/*.blade.php',
'./resources/js/**/*.vue',
'./resources/js/*.js',
'./resources/css/*.css',
'./vendor/gorlabs/tailwind-datatables/resources/views/**/*.blade.php',
'./vendor/gorlabs/tailwind-datatables/resources/js/**/*.js',
'./vendor/gorlabs/tailwind-datatables/**/*.{html,js,ts,jsx,tsx,vue,css}',
],
theme: {
extend: {
fontFamily: {
sans: ['Figtree', ...defaultTheme.fontFamily.sans],
},
colors: {
white: {
DEFAULT: 'rgb(var(--color-white) / <alpha-value>)',
// ... diğer white tonları ...
},
// Her renk için RGB formatında CSS değişkeni referansı
primary: {
DEFAULT: "rgb(var(--color-primary-DEFAULT) / <alpha-value>)",
light: "rgb(var(--color-primary-light) / <alpha-value>)",
"dark-light": "rgb(var(--color-primary-dark-light) / <alpha-value>)",
},
secondary: {
DEFAULT: "rgb(var(--color-secondary-DEFAULT) / <alpha-value>)",
light: "rgb(var(--color-secondary-light) / <alpha-value>)",
"dark-light": "rgb(var(--color-secondary-dark-light) / <alpha-value>)",
},
success: {
DEFAULT: "rgb(var(--color-success-DEFAULT) / <alpha-value>)",
light: "rgb(var(--color-success-light) / <alpha-value>)",
"dark-light": "rgb(var(--color-success-dark-light) / <alpha-value>)",
},
danger: {
DEFAULT: "rgb(var(--color-danger-DEFAULT) / <alpha-value>)",
light: "rgb(var(--color-danger-light) / <alpha-value>)",
"dark-light": "rgb(var(--color-danger-dark-light) / <alpha-value>)",
},
warning: {
DEFAULT: "rgb(var(--color-warning-DEFAULT) / <alpha-value>)",
light: "rgb(var(--color-warning-light) / <alpha-value>)",
"dark-light": "rgb(var(--color-warning-dark-light) / <alpha-value>)",
},
info: {
DEFAULT: "rgb(var(--color-info-DEFAULT) / <alpha-value>)",
light: "rgb(var(--color-info-light) / <alpha-value>)",
"dark-light": "rgb(var(--color-info-dark-light) / <alpha-value>)",
},
dark: {
DEFAULT: "rgb(var(--color-dark-DEFAULT) / <alpha-value>)",
light: "rgb(var(--color-dark-light) / <alpha-value>)",
"dark-light": "rgb(var(--color-dark-dark-light) / <alpha-value>)",
},
black: {
DEFAULT: 'rgb(var(--color-black) / <alpha-value>)', // Bu, bg-black'i senin --color-black değişkeninden almasını sağlar
// Eğer bg-opacity-50 gibi kullanımların kendi özel black rengin üzerinden olmasını istiyorsan
// veya doğrudan black renk paletine kendi değişkenlerini bağlamak istiyorsan:
50: 'rgb(var(--color-black-50) / <alpha-value>)', // varsayımsal: --color-black-50 varsa
// ... diğer black tonları ...
},
// DataTables ile ilişkili özel renkler
'dt-primary': {
DEFAULT: 'rgb(var(--color-dt-primary-DEFAULT) / <alpha-value>)',
dark: 'rgb(var(--color-dt-primary-dark) / <alpha-value>)',
light: 'rgb(var(--color-dt-primary-light) / <alpha-value>)',
},
},
},
},
plugins: [forms],
};
gorlabs-datatable/vite.config.js dosyanızı açın.
Dosyanın içeriğini aşağıdaki gibi tamamen değiştirin. Bu, v4.x'e özgü Vite pluginini kaldıracak ve v3.x için PostCSS yapılandırmasını ekleyecektir.
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import tailwindcssPlugin from '[@tailwindcss](https://github.com/tailwindcss)/postcss'; // Burası önemli
import autoprefixer from 'autoprefixer';
export default defineConfig({
plugins: [
laravel({
input: [
'resources/css/app.css',
'resources/js/app.js'
],
refresh: true,
}),
],
build: {
minify: true, // Minificaiton open
sourcemap: true, // Hata ayıklama için sourcemap oluştur
},
css: {
postcss: {
plugins: [
tailwindcssPlugin, // Ve burası
autoprefixer,
],
},
},
server: {
cors: true,
},
});
gorlabs-datatable/resources/css/app.css dosyanızı açın ve içeriğini aşağıdaki kodla tamamen değiştirin:
/* Import DataTables Responsive styles here and at the very beginning. */
[@import](https://github.com/import) 'tailwindcss';
[@tailwind](https://github.com/tailwind) base;
[@tailwind](https://github.com/tailwind) components;
[@tailwind](https://github.com/tailwind) utilities;
/* CSS variables for DataTables and other custom theme colors. */
:root {
/* Tailwind CSS Mavi Paleti */
--color-primary-DEFAULT: 59 130 246; /* blue-500: #3b82f6 */
--color-primary-light: 219 234 254; /* blue-100: #dbeafe */
--color-primary-dark-light: 191 219 254; /* blue-200: #bfdbfe */
--color-secondary-DEFAULT: 59 130 246; /* blue-500: #3b82f6 */
--color-secondary-light: 219 234 254; /* blue-100: #dbeafe */
--color-secondary-dark-light: 191 219 254;/* blue-200: #bfdbfe */
--color-success-DEFAULT: 59 130 246; /* blue-500: #3b82f6 */
--color-success-light: 219 234 254; /* blue-100: #dbeafe */
--color-success-dark-light: 191 219 254; /* blue-200: #bfdbfe */
--color-danger-DEFAULT: 59 130 246; /* blue-500: #3b82f6 */
--color-danger-light: 219 234 254; /* blue-100: #dbeafe */
--color-danger-dark-light: 191 219 254; /* blue-200: #bfdbfe */
--color-warning-DEFAULT: 59 130 246; /* blue-500: #3b82f6 */
--color-warning-light: 219 234 254; /* blue-100: #dbeafe */
--color-warning-dark-light: 191 219 254; /* blue-200: #bfdbfe */
--color-info-DEFAULT: 59 130 246; /* blue-500: #3b82f6 */
--color-info-light: 219 234 254; /* blue-100: #dbeafe */
--color-info-dark-light: 191 219 254; /* blue-200: #bfdbfe */
--color-dark-DEFAULT: 59 130 246; /* blue-500: #3b82f6 */
--color-dark-light: 219 234 254; /* blue-100: #dbeafe */
--color-dark-dark-light: 191 219 254; /* blue-200: #bfdbfe */
/* Bu kısımları orijinal bırakıyorum, ancak istiyorsan Tailwind gri/mavi tonlarına dönüştürebiliriz */
--dt-row-selected: 13, 110, 253; /* Maviye yakın bir ton */
--dt-row-selected-text: 255, 255, 255;
--dt-row-selected-link: 0, 0, 0;
--dt-row-stripe: 0, 0, 0;
--dt-row-hover: 0, 0, 0;
--dt-column-ordering: 0, 0, 0;
--dt-html-background: 255, 255, 255;
/* DataTables custom colors (dt-primary) - RGB FORMAT SEPARATED BY SPACES*/
--color-dt-primary-DEFAULT: 59 130 246; /* blue-500: #3b82f6 */
--color-dt-primary-dark: 29 78 216; /* blue-700: #1d4ed8 */
--color-dt-primary-light: 96 165 250; /* blue-400: #60a5fa */
}
/* Bazı özel durumlar için, doğrudan CSS kurallarına ihtiyacınız olabilir. */
gorlabs-datatable/resources/js/app.js dosyasını aç ve içeriğini aşağıdaki gibi güncelleyerek DataTables, Alpine.js ve diğer gerekli kütüphaneleri dahil et:
import './bootstrap';
import $ from 'jquery';
window.$ = window.jQuery = $;
import 'datatables.net';
import 'datatables.net-buttons';
import 'datatables.net-buttons/js/buttons.html5.js';
import 'datatables.net-buttons/js/buttons.print.js';
import 'datatables.net-buttons/js/buttons.colVis.js';
import 'datatables.net-responsive';
import "datatables.net-responsive-dt/css/responsive.dataTables.css";
import "../../resources/css/datatables-tailwind.css";
import '../../vendor/gorlabs/tailwind-datatables/resources/js/app';
php artisan make:model Post -mfs
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
use HasFactory;
protected $fillable = [
'title',
'content',
'published_at',
'is_published',
'status',
];
protected $casts = [
'is_published' => 'boolean',
'published_at' => 'datetime',
];
}
Oluşturulan migration dosyasını (ismi tarihe göre değişir) aç ve up() metodunu aşağıdaki gibi güncelle:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->text('content')->nullable();
$table->boolean('is_published')->default(false);
$table->timestamp('published_at')->nullable();
$table->string('status')->default('draft');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('posts');
}
};
<?php
namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* [@extends](https://github.com/extends) \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Post>
*/
class PostFactory extends Factory
{
/**
* Define the model's default state.
*
* [@return](https://github.com/return) array<string, mixed>
*/
public function definition(): array
{
return [
'title' => fake()->sentence(rand(3, 8)),
'content' => fake()->paragraphs(rand(1, 3), true),
'published_at' => fake()->optional(0.8)->dateTimeThisYear(), // %80 ihtimalle bir tarih verir
'is_published' => fake()->boolean(90), // %90 ihtimalle true
'status' => fake()->randomElement(['draft', 'published', 'archived']),
];
}
}
<?php
namespace Database\Seeders;
use App\Models\Post;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
class PostSeeder extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void
{
Post::factory()->count(50)->create();
}
}
namespace Database\Seeders;
use App\Models\User;
// use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
/**
* Seed the application's database.
*/
public function run(): void
{
User::factory(10)->create(); // Varsayılan kullanıcı seeder
$this->call([
PostSeeder::class,
]);
}
}
Terminalde gorlabs-datatable projenin kök dizinindeyken bu komutu çalıştır:
php artisan migrate:fresh --seed
php artisan datatable:make PostsDataTable --model=Post
<?php
namespace App\DataTables;
use App\Models\Post;
use Illuminate\Database\Eloquent\Builder as QueryBuilder;
use Yajra\DataTables\EloquentDataTable;
use Yajra\DataTables\Html\Builder as HtmlBuilder;
use Yajra\DataTables\Html\Button;
use Yajra\DataTables\Html\Column;
use Yajra\DataTables\Services\DataTable;
class PostsDataTable extends DataTable
{
public function query(Post $model): QueryBuilder
{
return $model->newQuery();
}
public function dataTable(QueryBuilder $query): EloquentDataTable
{
return (new EloquentDataTable($query))
->setRowId('id')
->addColumn('select_checkbox', function(Post $post) {
return '';
})
->addColumn('actions', function(Post $post) {
return '';
})
->editColumn('is_published', function(Post $post) {
return $post->is_published ? 1 : 0;
})
->editColumn('published_at', function(Post $post) {
return $post->published_at ? $post->published_at->format('Y-m-d H:i:s') : null;
})
->editColumn('title', function(Post $post) {
$title = $post->title;
if (strlen($title) > 24) {
return substr($title, 0, 24) . ' ...';
}
return $title;
})
->editColumn('content', function(Post $post) {
$content = $post->content;
if (strlen($content) > 34) {
return substr($content, 0, 34) . ' ...';
}
return $content;
});
}
public function html(): HtmlBuilder
{
return $this->builder()
->setTableId('posts-table')
->columns($this->getColumns())
->minifiedAjax()
->orderBy(1)
->select(false)
->buttons([
Button::make('create'),
Button::make('export'),
Button::make('print'),
Button::make('reset'),
Button::make('reload')
]);
}
public function getColumns(): array
{
$columns = [
Column::computed('select_checkbox')
->title('<input type="checkbox" id="select-all-checkbox" class="rounded border-gray-300 text-indigo-600 shadow-sm focus:ring-indigo-500">')
->exportable(false)
->printable(false)
->width(10)
->addClass('text-center')
->orderable(false)
->searchable(false)
->footer('')
->responsivePriority(1),
Column::make('id')->responsivePriority(2),
Column::make('title')->responsivePriority(3),
Column::make('content')->responsivePriority(5),
Column::make('published_at')
->title('Published At')
->width(150)
->responsivePriority(4),
Column::make('is_published')
->title('Published')
->width(100)
->responsivePriority(4),
Column::make('status')->responsivePriority(4),
];
$columns[] = Column::computed('actions')
->title('ACTIONS')
->exportable(false)
->printable(false)
->width(120)
->addClass('text-center')
->orderable(false)
->searchable(false)
->footer('')
->responsivePriority(1);
return $columns;
}
protected function filename(): string
{
return 'Posts_' . date('YmdHis');
}
}
Terminalde gorlabs-datatable projenin kök dizinindeyken aşağıdaki komutu çalıştır:
php artisan make:controller PostController --resource
<?php
namespace App\Http\Controllers;
use App\DataTables\PostsDataTable;
use App\Models\Post;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
class PostController extends Controller
{
/**
* Display a listing of the resource.
* DataTable'ı göstermek için ana view'ı döndürür.
*/
public function index()
{
return view('posts.index');
}
/**
* Process datatables ajax request.
* Yajra DataTables'tan gelen AJAX isteğini işler ve JSON yanıtı döndürür.
*
* [@param](https://github.com/param) PostsDataTable $dataTable DataTable sınıfının örneği (dependency injection ile).
* [@return](https://github.com/return) JsonResponse
*/
public function ajaxData(PostsDataTable $dataTable)
{
Log::info('DataTables AJAX isteği parametreleri:', request()->all());
// DataTable'ın query metodunu kullanarak verileri çeker ve işler.
return $dataTable->dataTable($dataTable->query(new Post()))->make(true);
}
/**
* Show the form for creating a new resource.
* Yeni bir post oluşturmak için formu gösterir (modal içinde yüklenecek).
*/
public function create()
{
// Boş bir Post modeli örneği göndererek formun boş başlamasını sağlarız.
// Bu, `postForm` Alpine bileşeninin `initialPost` config'ini besler.
return view('tailwind-datatables::datatables.form', ['post' => new Post()]);
}
/**
* Store a newly created resource in storage.
* Yeni oluşturulan post verilerini veritabanına kaydeder.
*
* [@param](https://github.com/param) Request $request Gelen HTTP isteği.
* [@return](https://github.com/return) JsonResponse
*/
public function store(Request $request)
{
// Gelen isteği doğrula (validation).
$request->validate([
'title' => 'required|string|max:255',
'content' => 'nullable|string',
// 'is_published' alanı checkbox'tan geldiği için bazen 'on' veya null olabilir.
// Laravel'in validate'i boolean için bunu otomatik dönüştürebilir,
// ancak manuel kontrol daha güvenli olabilir.
'is_published' => 'nullable|boolean', // nullable ekledik
'published_at' => 'nullable|date',
]);
// published_at alanı boş gelirse null yap veya karbon objesine dönüştür.
$data = $request->except(['published_at']); // published_at'ı ayrı ele alıyoruz
$data['published_at'] = $request->input('published_at') ? now()->parse($request->input('published_at')) : null;
$data['is_published'] = (bool) $request->input('is_published', 0); // checkbox değeri varsa true, yoksa false
$post = Post::create($data); // Post modelini kullanarak yeni kayıt oluştur.
// Başarılı yanıtı JSON olarak döndür.
return response()->json(['success' => 'Post başarıyla oluşturuldu.', 'post' => $post]);
}
/**
* Show the form for editing the specified resource.
* Belirtilen postu düzenlemek için formu gösterir (modal içinde yüklenecek).
*
* [@param](https://github.com/param) Post $post Düzenlenecek Post modeli (Route Model Binding).
* [@return](https://github.com/return) \Illuminate\View\View
*/
public function edit(Post $post)
{
// `datetime-local` inputu için `YYYY-MM-DDTHH:mm` formatında bir string hazırlıyoruz.
// Eğer published_at null ise boş string gönderiyoruz.
$post->published_at_formatted = $post->published_at ? $post->published_at->format('Y-m-d\TH:i') : '';
// Mevcut post verisini `posts.form` view'ına gönderiyoruz.
// Bu, `postForm` Alpine bileşeninin `initialPost` config'ini besler.
return view('tailwind-datatables::datatables.form', compact('post'));
}
/**
* Update the specified resource in storage.
* Belirtilen...
How can I help you explore Laravel packages today?