PHPackages                             mimisk/pinakas - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Framework](/categories/framework)
4. /
5. mimisk/pinakas

ActiveLibrary[Framework](/categories/framework)

mimisk/pinakas
==============

A simple, reusable Laravel table builder package for fast CRUD listings.

v0.0.1(1mo ago)00MITPHPPHP ^8.2CI passing

Since Apr 24Pushed 1mo ago1 watchersCompare

[ Source](https://github.com/MimisK13/pinakas)[ Packagist](https://packagist.org/packages/mimisk/pinakas)[ Docs](https://github.com/MimisK13/pinakas)[ RSS](/packages/mimisk-pinakas/feed)WikiDiscussions main Synced 1w ago

READMEChangelogDependencies (6)Versions (2)Used By (0)

[![Pinakas table preview](images/pinakas.png)](images/pinakas.png)

 [![Tests](https://github.com/MimisK13/pinakas/actions/workflows/tests.yml/badge.svg)](https://github.com/MimisK13/pinakas/actions/workflows/tests.yml) [![Latest Version on Packagist](https://camo.githubusercontent.com/29b40c6b386a610f62e9ad7a8564e120e9e4ac98affb375061658828413a9976/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6d696d69736b2f70696e616b61732e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/mimisk/pinakas) [![Total Downloads](https://camo.githubusercontent.com/f2c08fbe342900eb747bdc5f238e3602ce4de3ef67fbf547da7148f21c7e76ef/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6d696d69736b2f70696e616b61732e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/mimisk/pinakas) [![License: MIT](https://camo.githubusercontent.com/55c0218c8f8009f06ad4ddae837ddd05301481fcf0dff8e0ed9dadda8780713e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d627269676874677265656e2e7376673f7374796c653d666c61742d737175617265)](LICENSE)

Pinakas is a simple, reusable Laravel table builder package focused on fast CRUD listings.

Requirements
------------

[](#requirements)

- PHP `^8.2`
- Laravel `^11.0`, `^12.0`, or `^13.0`

Installation
------------

[](#installation)

Via Composer

```
composer require mimisk/pinakas
```

Install JS dependencies for the interactive controls:

```
npm install alpinejs @tailwindplus/elements
```

Publish package JS asset:

```
php artisan vendor:publish --tag=pinakas-assets
```

Import Alpine and Pinakas JS in your app entrypoint (`resources/js/app.js`):

```
import Alpine from 'alpinejs';
import './vendor/pinakas/pinakas';

window.Alpine = Alpine;
Alpine.start();
```

Rebuild assets:

```
npm run build
```

If your app already starts Alpine (for example through Breeze), only import the published Pinakas JS asset once:

```
import './vendor/pinakas/pinakas';
```

For Vite dev servers using a custom local domain, make sure HMR uses the same lowercase host as the browser URL. Example:

```
// vite.config.js
export default defineConfig({
    server: {
        hmr: {
            host: 'packages.test',
        },
        watch: {
            ignored: [
                '**/vendor/**',
                '**/packages/**/vendor/**',
                '**/storage/debugbar/**',
                '**/public/build/**',
            ],
        },
    },
});
```

Configuration
-------------

[](#configuration)

Publish config:

```
php artisan vendor:publish --tag=pinakas-config
```

`config/pinakas.php`:

```
'empty_state' => [
    'title' => 'No records found',
    'description' => 'There are no rows available yet.',
    'search_title' => 'No matching results',
    'search_description' => 'Try a different keyword or clear your search.',
],

'search' => [
    'enabled' => false,
    'query_name' => 'search',
    'show_label' => true,
    'label' => 'Search',
    'placeholder' => 'Search...',
    'rounded' => 'rounded-none',
    'debounce_ms' => 350,
    'min_chars' => 3,
    'icon' => 'magnifying-glass',
],

'sorting' => [
    'enabled' => false,
    'query_name' => 'sort',
    'direction_query_name' => 'direction',
    'default_direction' => 'asc',
    'icon_position' => 'right', // left | right
],

'bulk' => [
    'selected_input_name' => 'selected_ids',
    'actions' => [],
],

'ui' => [
    'accent_color' => 'amber-600',
    'table_bordered' => false,
    'table_rounded' => 'rounded-xs',
    'table_striped' => false,
    'table_hoverable' => true,
    'pagination_dropdown_rounded' => 'rounded-none',
    'action_button_rounded' => 'rounded-none',
    'action_dropdown_rounded' => 'rounded-none',
],

'columns' => [
    'date_format' => 'd-m-Y',
    'time_format' => 'H:i',
],

'pagination' => [
    'enabled' => false,
    'default_per_page' => 15,
    'page_name' => 'page',
    'per_page_query_name' => 'per_page',
    'per_page_options' => [10, 25, 50],
    'show_label' => false,
    // Available: default, centered-page-numbers
    'template' => 'default',
],
```

These are global defaults and can be overridden per table.

Usage
-----

[](#usage)

### Quick Start

[](#quick-start)

```
use App\Models\User;
use Mimisk\Pinakas\Actions\ActionGroup;
use Mimisk\Pinakas\Actions\DeleteAction;
use Mimisk\Pinakas\Actions\EditAction;
use Mimisk\Pinakas\Actions\ViewAction;
use Mimisk\Pinakas\Bulk\BulkAction;
use Mimisk\Pinakas\Columns\BadgeColumn;
use Mimisk\Pinakas\Columns\BooleanColumn;
use Mimisk\Pinakas\Columns\Column;
use Mimisk\Pinakas\Columns\DateColumn;
use Mimisk\Pinakas\Columns\TimeColumn;
use Mimisk\Pinakas\Pinakas;

$table = (new Pinakas())
    ->model(User::class)
    ->columns([
        Column::make('Id', 'id')->searchable()->sortable(),
        Column::make('Name', 'name')->searchable()->sortable(),
        Column::make('Email', 'email')->searchable()->sortable(),
        DateColumn::make('Created At', 'created_at')->format('d/m/Y H:i')->sortable(),
    ])
    ->actions([
        ActionGroup::make([
            ViewAction::make(),
            EditAction::make(),
            DeleteAction::make(),
        ]),
    ])
    ->bulkActions([
        BulkAction::make('Delete Selected')
            ->icon('trash')
            ->url('/users/bulk-delete')
            ->method('DELETE')
            ->confirm('Delete selected users?'),
    ])
    ->paginate(10)
    ->searchable()
    ->sortable()
    ->uiAccentColor('amber-600')
    ->bordered(true)
    ->tableRounded('rounded-xs')
    ->paginationDropdownRounded('rounded-none')
    ->actionButtonRounded('rounded-none')
    ->actionDropdownRounded('rounded-none')
    ->perPageOptions([10, 25, 50]);
```

### Rendering The Table View

[](#rendering-the-table-view)

Pass the table object to your Blade view:

```
return view('welcome', [
    'table' => $table,
]);
```

Render the package table in Blade:

```
@include('pinakas::table', ['table' => $table])
```

### Columns

[](#columns)

Define columns with label + model attribute:

```
->columns([
    Column::make('Id', 'id'),
    Column::make('Name', 'name'),
    Column::make('Email', 'email'),
    Column::make('Created At', 'created_at'),
])
```

Column alignment:

```
->columns([
    Column::make('Id', 'id')->align('center'), // header + cells
    Column::make('Name', 'name')->align('left'),
    Column::make('Amount', 'amount')->align('right'),
])
```

Header alignment (independent from cell alignment):

```
->columns([
    Column::make('Amount', 'amount')
        ->cellAlign('right')    // cells only
        ->headerAlign('center') // header
])
```

Header label is optional in `make()`. If omitted, it is auto-generated from the attribute:

```
->columns([
    Column::make(attribute: 'created_at'), // "Created At"
    DateColumn::make(attribute: 'email_verified_at'), // "Email Verified At"
])
```

Date column type:

```
use Mimisk\Pinakas\Columns\DateColumn;

->columns([
    DateColumn::make('Created At', 'created_at')
        ->format('d/m/Y H:i')
        ->timezone('Europe/Athens')
        ->emptyText('-'),
])
```

If `->format(...)` is omitted, DateColumn uses `columns.date_format` from config.

Time column type:

```
use Mimisk\Pinakas\Columns\TimeColumn;

->columns([
    TimeColumn::make('Login Time', 'last_login_at')
        ->format('H:i')
        ->timezone('Europe/Athens')
        ->emptyText('-'),
])
```

If `->format(...)` is omitted, TimeColumn uses `columns.time_format` from config.

Badge column type:

```
use Mimisk\Pinakas\Columns\BadgeColumn;

->columns([
    BadgeColumn::make('Status', 'status')
        ->color(fn ($value) => filled($value) ? 'green' : 'gray'),
])
```

Boolean column type:

```
use Mimisk\Pinakas\Columns\BooleanColumn;

->columns([
    BooleanColumn::make('Verified', 'is_verified')
        ->labels('Verified', 'Not verified')
        ->colors('green', 'gray'),
])
```

### Actions (Single And Group)

[](#actions-single-and-group)

Single actions:

```
->actions([
    ViewAction::make(),
    EditAction::make(),
    DeleteAction::make(),
])
```

Grouped actions:

```
->actions([
    ActionGroup::make([
        ViewAction::make(),
        EditAction::make(),
        DeleteAction::make(),
    ]),
])
```

Custom action URLs may be generated directly or through named routes:

```
Action::make('Open')
    ->route('user.show', fn ($row) => ['user' => $row->id])
```

Destructive actions can show a confirmation modal before submit:

```
Action::make('Delete')
    ->url('/users/1')
    ->method('DELETE')
    ->confirm('Delete this user?')
```

`DeleteAction::make()` uses the Laravel-style `*.destroy` route name.

Confirmation modals are rendered by `pinakas::partials.confirm-modal`. Pinakas also ships `pinakas::partials.styles` for the required `x-cloak`rule, preventing Alpine dropdown/modal flashes while the page initializes.

### Pagination

[](#pagination)

Enable pagination:

```
->paginate(10)
```

Second parameter defines page query key:

```
->paginate(10, 'users_page')
```

Third parameter is optional label text (shown above dropdown):

```
->paginate(10, 'users_page', 'Per Page')
```

Pagination template override per table:

```
->paginationTemplate('centered-page-numbers')
```

You can also pass a direct view name:

```
->paginationTemplate('my-custom.pagination')
```

### Search

[](#search)

Enable global search:

```
->searchable()
```

Custom search query key:

```
->searchable('q')
```

Override label / placeholder / icon per table:

```
->searchLabel('Find User')
->searchPlaceholder('Type name or email')
->searchRounded('rounded-none')
->searchDebounceMs(300)
->searchMinChars(3)
->searchIcon('magnifying-glass') // or 'search', null, or custom view name
```

Hide label or icon:

```
->showSearchLabel(false)
->searchIcon(null)
```

Mark specific columns as searchable:

```
->columns([
    Column::make('Name', 'name')->searchable(),
    Column::make('Email', 'email')->searchable(),
    Column::make('Created At', 'created_at'), // not searchable
])
```

If no columns are marked, search is applied to all defined column attributes.

### Sorting

[](#sorting)

Enable sorting support for this table:

```
->sortable()
```

Set icon position per table (override config):

```
->sortIconPosition('right') // or 'left'
```

Custom sort query keys:

```
->sortable('sort_by', 'sort_direction')
```

Mark sortable columns:

```
->columns([
    Column::make('Id', 'id')->sortable(),
    Column::make('Name', 'name')->sortable(),
    Column::make('Email', 'email')->sortable(),
])
```

You can combine `->searchable()` and `->sortable()` safely. Only columns marked with `->sortable()` become sortable.

### Bulk Actions

[](#bulk-actions)

Register bulk actions:

```
use Mimisk\Pinakas\Bulk\BulkAction;

->bulkActions([
    BulkAction::make('Delete Selected')
        ->icon('trash')
        ->url('/users/bulk-delete')
        ->method('DELETE')
        ->confirm('Delete selected users?'),
])
```

Customize selected IDs input name:

```
->bulkSelectedInputName('ids')
```

Controller endpoint example:

```
public function bulkDelete(Request $request)
{
    $ids = $request->input('selected_ids', []);
    User::query()->whereIn('id', $ids)->delete();

    return back();
}
```

### UI Settings

[](#ui-settings)

Override global accent color per table:

```
->uiAccentColor('amber-600')
```

You may also pass CSS color values:

```
->uiAccentColor('#d97706')
```

Control outer table border per table:

```
->bordered(true)  // show border
->bordered(false) // hide border
```

Control table rounded class per table:

```
->tableRounded('rounded-xs')
->tableRounded('rounded-lg')
->tableRounded('rounded-none')
```

Control striped rows per table:

```
->striped()       // ON
->striped(false)  // OFF
```

Control hoverable rows per table:

```
->hoverable()       // ON
->hoverable(false)  // OFF
```

Control rounded classes for controls:

```
->paginationDropdownRounded('rounded-none')
->actionButtonRounded('rounded-none')
->actionDropdownRounded('rounded-none')
```

### Per-Page Selector

[](#per-page-selector)

`Per page` dropdown appears automatically when pagination is enabled. No label is shown by default.

`el-select` is powered by `@tailwindplus/elements` (npm).

```
->perPageOptions([10, 25, 50])
```

Custom per-page query key:

```
->perPageOptions([10, 25, 50], 'users_per_page')
```

Label visibility is controlled globally by `pagination.show_label`. If `show_label = true` and no custom text is passed, default text is `Per page`.

### Loading State

[](#loading-state)

The table includes a built-in loading overlay (spinner + reduced opacity) while form submissions and link navigations are in progress. The UI classes include dark mode variants for table, controls, and loading state.

### Empty States

[](#empty-states)

When the table has no data:

```
->emptyState('No users yet', 'Create your first user to get started.')
```

When search has no matches:

```
->searchEmptyState('No users found', 'Try another term or clear search.')
```

### Full Controller Example

[](#full-controller-example)

```
