{"id":24822981,"url":"https://github.com/asosick/filament-layout-manager","last_synced_at":"2025-07-25T00:15:26.886Z","repository":{"id":274714062,"uuid":"923327550","full_name":"asosick/filament-layout-manager","owner":"asosick","description":"A filamentphp plugin which enables user page customization using any livewire component","archived":false,"fork":false,"pushed_at":"2025-03-04T15:56:54.000Z","size":26104,"stargazers_count":28,"open_issues_count":1,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-25T22:17:51.002Z","etag":null,"topics":["filamentphp","laravel","livewire","php"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/asosick.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":".github/CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":".github/SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"asosick"}},"created_at":"2025-01-28T03:08:08.000Z","updated_at":"2025-03-24T16:11:57.000Z","dependencies_parsed_at":"2025-03-04T16:34:20.674Z","dependency_job_id":"ef8e3b47-55f0-44f1-b8fa-c43d3d90c681","html_url":"https://github.com/asosick/filament-layout-manager","commit_stats":null,"previous_names":["asosick/reorder-widgets","asosick/filament-layout-manager"],"tags_count":6,"template":false,"template_full_name":"filamentphp/plugin-skeleton","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/asosick%2Ffilament-layout-manager","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/asosick%2Ffilament-layout-manager/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/asosick%2Ffilament-layout-manager/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/asosick%2Ffilament-layout-manager/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/asosick","download_url":"https://codeload.github.com/asosick/filament-layout-manager/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248507466,"owners_count":21115606,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["filamentphp","laravel","livewire","php"],"created_at":"2025-01-30T19:26:03.798Z","updated_at":"2025-04-12T02:40:42.510Z","avatar_url":"https://github.com/asosick.png","language":"PHP","funding_links":["https://github.com/sponsors/asosick"],"categories":[],"sub_categories":[],"readme":"# Filament Layout Manager\n\n[![Latest Version on Packagist](https://img.shields.io/packagist/v/asosick/filament-layout-manager.svg?style=flat-square)](https://packagist.org/packages/asosick/filament-layout-manager)\n[![GitHub Tests Action Status](https://img.shields.io/github/actions/workflow/status/asosick/filament-layout-manager/run-tests.yml?branch=main\u0026label=tests\u0026style=flat-square)](https://github.com/asosick/filament-layout-manager/actions?query=workflow%3Arun-tests+branch%3Amain)\n[![Total Downloads](https://img.shields.io/packagist/dt/asosick/filament-layout-manager.svg?style=flat-square)](https://packagist.org/packages/asosick/filament-layout-manager)\n\n### Allow users to create \u0026 customize their own FilamentPHP pages composed of Livewire components\n### Demo\n![demo.gif](https://raw.githubusercontent.com/asosick/filament-layout-manager/main/demo.gif)\n\n## Table of Contents\n\n- [Installation](#installation)\n- [Usage](#usage)\n    - [Generate a new page](#1-generate-a-new-page)\n    - [Extend your page from LayoutManagerPage](#2-extend-your-page-from-layoutmanagerpage)\n    - [Remove auto-generated $view property](#3-remove-auto-generated-view-property)\n    - [Define your components](#4-define-your-components)\n    - [Passing Widget Data](#passing-widget-data)\n    - [Renaming Selection Options](#renaming-selection-options)\n- [Multiple Layouts](#multiple-layouts)\n- [Customization](#customization)\n    - [Extend LayoutManager](#2-extend-layoutmanager)\n    - [Update Config](#3-update-config)\n- [Saving Layouts to a Database](#saving-layouts-to-a-database)\n- [Adding Header Actions](#adding-header-actions)\n- [Wrapping in a FilamentPHP page](#optional-wrapping-in-a-filamentphp-page)\n- [Child Component Data Stores](#child-component-data-stores)\n    - [Why is this useful?](#why-is-this-useful)\n    - [Event Hook](#event-hook)\n    - [Updating the component's store](#updating-the-components-store)\n    - [Using the store](#using-the-store)\n    - [Customizing](#customizing)\n- [Changelog](#changelog)\n- [Contributing](#contributing)\n- [Security Vulnerabilities](#security-vulnerabilities)\n- [Credits](#credits)\n- [Open For Work](#open-for-work)\n- [License](#license)\n\n\n## Installation\n\nYou can install the package via composer:\n\n```bash\ncomposer require asosick/filament-layout-manager\n```\n\nYou can publish the config file with:\n\n```bash\nphp artisan vendor:publish --tag=\"filament-layout-manager-config\"\n```\n\nOptionally, you can publish the views using\n\n```bash\nphp artisan vendor:publish --tag=\"filament-layout-manager-views\"\n```\n\nOptionally, you can publish the translation files using\n```bash\nphp artisan vendor:publish --tag=\"filament-layout-manager-translations\"\n```\n\n## Usage\nThe easiest way to use Filament Layout Manager is by creating a new page.\n\n### 1. Generate a new page\n```bash\n# Replace TestPage with your new page's name\nphp artisan make:filament-page TestPage\n```\n\n### 2. Extend your page from `LayoutManagerPage`\n\nYour custom page needs to extend from `use Asosick\\FilamentLayoutManager\\Pages\\LayoutManagerPage;`\n\n```php\nuse Asosick\\FilamentLayoutManager\\Pages\\LayoutManagerPage;\nclass TestPage extends LayoutManagerPage {}\n```\n\n### 3. Remove auto-generated $view property\nTo ensure to correct view is rendered, please delete the autogenerated view property in your new Page class. The view to be used is defined in `LayoutManagerPage` and this property overrides it.\n```php\nuse Asosick\\FilamentLayoutManager\\Pages\\LayoutManagerPage;\nclass TestPage extends LayoutManagerPage\n{\n //    protected static string $view = 'filament.pages.custom-page'; \u003c- DELETE OR COMMENT THIS\n}\n```\n\n\n### 4. Define your components\n\nYou can now define the livewire components you'd like users to be able to add to this new page using the `getComponents()` method:\n```php\nclass TestPage extends LayoutManagerPage\n{\n    protected function getComponents(): array\n    {\n        // Replace with your chosen components\n        return [\n            LivewireComponent::class,\n            CompaniesWidget::class,\n            BlogPostsChart::class,\n        ];\n    }\n}\n```\nYou can now visit your page, unlock your layout, and begin reorganizing.\n\n### Passing Widget Data\nSimilar to a traditional filament page, you are able to pass data directly to your widgets. (Support for passing data to custom components coming soon...)\n\n***NOTE: Data passed to this widget will be applied to all its instances. For component specific data, see section below on component data stores***\n\n```php\nclass TestPage extends LayoutManagerPage\n{\n    protected function getComponents(): array\n    {\n        return [\n            CompaniesWidget::make([\n                'company' =\u003e 'Apple'\n            ]),\n        ];\n    }\n}\n```\nThis passes your data `['company'=\u003e'Apple']` to your widget in a `data` property. You can access that in your `mount()` function or via a direct property like any Livewire component.\n```php\nclass CompaniesWidget extends BaseWidget\n{\n    public array $data;\n    public function mount(array $data){\n        $this-\u003edata = $data;\n    }\n//... other methods \u0026 properties\n}\n```\n\n### Renaming Selection Options\nThe names associated with your selected components can be changed by overriding the `getComponentSelectOptions` method in your custom page. Be sure to order the array you provided to match the order of the components you provided\n\n```php\nclass TestPage extends LayoutManagerPage\n{\n    protected function getComponents(): array\n    {\n        return [\n            CompaniesWidget::class, //Default select option is `CompaniesWidget`\n        ];\n    }\n\n    protected function getComponentSelectOptions(): array\n    {\n        return ['My Company Widget'];\n    }\n}\n```\n\n## Multiple Layouts\nUsers are able to define multiple layouts they can switch between.\n\nEach layout is mapped to a keybinding based on its number:\n* `command+1 | ctrl+1` =\u003e layout 1\n* `command+2 | ctrl+2` =\u003e layout 2 \n* so forth...\n\nChange the default number of views using the `getLayoutCount()` function in your page class or update the configuration file.\n\n## Customization\nFilament Layout Manager wraps your Livewire components inside a customizable class, allowing users to modify them.\n\nThis wrapper class is different from your Page class or its Blade view. The Page class renders the wrapper component, while the wrapper enables user manipulation of Livewire components.\n\nThe wrapper class that must be extended to enable customization is `Asosick\\FilamentLayoutManager\\Http\\Livewire\\LayoutManager.php`\n\nIn order to customize say the colour of one of the header buttons, first:\n\n#### 1) Publish the configuration file\n```bash\nphp artisan vendor:publish --tag=\"filament-layout-manager-config\"\n```\n#### 2) Extend LayoutManager\nCreate a new class in your application called (for example) `App\\Livewire\\CustomLayoutManager.php` \nand extend that class off of `Asosick\\FilamentLayoutManager\\Http\\Livewire\\LayoutManager.php`\n\n```php\nnamespace App\\Livewire;\nuse Asosick\\FilamentLayoutManager\\Http\\Livewire\\LayoutManager;\nuse Filament\\Actions\\Action;\n\nclass CustomLayoutManager extends LayoutManager\n{\n    /* Example of changing the colour of the add button to red */\n    public function addAction(): Action\n    {\n        return parent::addAction()-\u003ecolor('danger');\n    }\n}\n```\n#### 3) Update config\nUpdate your configuration to point to your new custom class.\n```php\n// newly published config file\nreturn [\n    'layout_manager' =\u003e \\App\\Livewire\\CustomLayoutManager::class,\n    // Other settings \n    // ...\n];\n```\n\nI recommend exploring the code in `LayoutManager` when digging into customization. You'll want to ensure you're still calling the require methods on actions you edit.\n\n\n\n### Saving Layouts to a Database\nBy default, layouts are saved in the user's session and are not persisted\n\nIn order to save your user's layout to a database (or file, etc.), you'll need to\n1. Override `LayoutManager` as shown above\n2. Implement a new `save()` function to persist the layout\n3. Implement a new `load()` function to load the layout\n\n**Where a user's layout is saved in your database and how that is managed is your concern.**\n\nThere needs to be somewhere to store this information. Perhaps a json column on your user's table called `settings` for example. You'll need to create a column if it doesn't exist in your DB.\n\n#### Example\nAssumes a `settings` json column on your user's model where settings can be stored.\n\n```php\nnamespace App\\Livewire;\n\nuse Asosick\\FilamentLayoutManager\\Http\\Livewire\\LayoutManager;\nuse Illuminate\\Support\\Arr;\n\nclass CustomLayoutManager extends LayoutManager\n{\n    public function save(): void\n    {\n        $user = auth()-\u003euser();\n        $user-\u003esettings = [\n            'container' =\u003e $this-\u003econtainer\n        ];\n        $user-\u003esave();\n    }\n\n    public function load(): void\n    {\n        $user = auth()-\u003euser();\n        $this-\u003econtainer = Arr::get(\n            json_decode($user-\u003esettings, true),\n            'container',\n            []\n        );\n    }\n}\n```\n\n### Adding Header Actions\nHeader actions can be added to the right of the 'Lock' button by overriding the `getHeaderActions()` method in your custom LayoutManager (*NOT your custom page*).\n\nExample:\n```php\nnamespace App\\Livewire;\n\nuse Asosick\\FilamentLayoutManager\\Http\\Livewire\\LayoutManager;\nuse Filament\\Actions\\Action;\nuse Illuminate\\Support\\Facades\\Log;\n\nclass CustomLayoutManager extends LayoutManager\n{\n    public function getHeaderActions(): array\n    {\n        return [\n            Action::make('hello')\n                -\u003eaction(fn () =\u003e Log::info('hello world!')),\n            Action::make('goodbye')\n                -\u003eaction(fn () =\u003e Log::info('goodbye world!')),\n        ];\n    }\n}\n```\n\n\n#### (Optional) Wrapping in a FilamentPHP page\nBy default, the LayoutManagerPage is not rendered with the traditional FilamentPHP page tags. If, for some reason, you need everything wrapped in a FilamentPHP page, you can enable that as so:\n\n```php\nnamespace App\\Filament\\Pages;\nuse Asosick\\FilamentLayoutManager\\Pages\\LayoutManagerPage;\nuse Filament\\Actions\\Action;\n\nclass TestPage extends LayoutManagerPage\n{\n    /* Wrap the LayoutManager component in a traditional filament page */\n    public function shouldWrapInFilamentPage(): bool\n    {\n        return true;\n    }\n\n    /* Can now use existing filament header actions */\n    protected function getHeaderActions(): array\n    {\n        return [\n            Action::make('my-header-action')\n        ];\n    }\n}\n```\n\nor\n```php\n/* In filament-layout-manage.php config file */\n'wrap_in_filament_page' =\u003e true,\n```\nYou may need to override some filament css hooks to get the spacing right for what you need.\n\n## Child Component Data Stores\nComponents can save data about themselves (like table filters or form values) and restore it when the user returns to the page.\n\n#### Why is this useful?\nFor example, in my application, I wanted table widgets to remember the filters users applied across sessions.\n\nFilament does provide a `persistToSession()` option for tables, but this does not work for multiple table widgets or across sessions.\n\n### Event Hook\nI've provided a livewire event for you to utilize for this purpose.\n\nEach livewire component rendered through your layout manager is passed a value called `container_key` used to keep track of its data. \nComponent specific data is passed via the `store` property.\n\nEach livewire component can dispatch an event to the `LayoutManager` class to update it's `store` which is saved alongside your layout data.\n\n### Getting the component key and store\n\nDefine the container_key and store properties in your widget or component class\n```php\n/* \nProvide the following as part of your child component (like a widget class), to get the id and your data (in store).\n*/\npublic string $container_key;\npublic array $store;\n\npublic function mount(string $container_key, array $store){\n    $this-\u003econtainer_key = $container_key;\n    $this-\u003estore = $store;\n}\n```\n\n### Updating the component's store\nExecute the following anywhere in your child-component (like a table widget), while replacing the `store: []` with actual data.\n```php\n$this-\u003edispatch('component-store-update',\n    id: $this-\u003econtainer_key,\n    store: []\n);\n```\n(For example, I dispatch the above in my table widget where store is all the current table filters)\n\n\n### Using the store\nYour components `store` property is passed just like any livewire property on reloads of your layout.\n\n### Customizing\nThis `component-store-update` event method is present in `LayoutManager` meaning if you want to change it's behaviour, you are free to do so in your custom layout manager.\n\nHow to create a custom layout manager is detailed above in this README.\n\n[//]: # (This is the contents of the published config file:)\n\n[//]: # ()\n[//]: # (```php)\n\n[//]: # (return [)\n\n[//]: # (];)\n\n[//]: # (```)\n[//]: # ()\n[//]: # (## Usage)\n\n[//]: # ()\n[//]: # (```php)\n\n[//]: # ($reorderWidgets = new Asosick\\ReorderWidgets\u0026#40;\u0026#41;;)\n\n[//]: # (echo $reorderWidgets-\u003eechoPhrase\u0026#40;'Hello, Asosick!'\u0026#41;;)\n\n[//]: # (```)\n\n[//]: # ()\n[//]: # (## Testing)\n\n[//]: # ()\n[//]: # (```bash)\n\n[//]: # (composer test)\n\n[//]: # (```)\n\n## Changelog\n\nPlease see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.\n\n## Contributing\n\nPlease see [CONTRIBUTING](.github/CONTRIBUTING.md) for details. All contributors welcome - don't be shy :)\n\n## Security Vulnerabilities\n\nPlease review [our security policy](../../security/policy) on how to report security vulnerabilities.\n\n## Credits\n\n- [August](https://github.com/asosick)\n- [All Contributors](../../contributors)\n\n## Open for work\nEnjoy this package and looking for a Laravel developer to join your team? Shoot me a message on [LinkedIn](https://www.linkedin.com/in/asosick/) or via email at [august@sosick.ca](mailto:august@sosick.ca)!\n\nI am based out of Toronto, Ontario, Canada, but I am open to all development opportunities, Laravel or otherwise!\n\n## License\n\nThe MIT License (MIT). Please see [License File](LICENSE.md) for more information.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fasosick%2Ffilament-layout-manager","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fasosick%2Ffilament-layout-manager","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fasosick%2Ffilament-layout-manager/lists"}