Full-screen page preview modal for Filament

Overview

Peek

Build Status Latest Stable Version Total Downloads License

A Filament plugin that adds a full-screen preview modal to your Edit pages. The modal can be used before saving to preview a modified record.

Screenshots of the edit page and preview modal

Installation

You can install the package via composer:

composer require pboivin/filament-peek:"^0.3"

The requirements are PHP 8.0 and Filament 2.0

Demo Project

For an easy way to try out the plugin on a simple Filament project, have a look at the filament-peek-demo repository.

Configuration

You can publish the config file with:

php artisan vendor:publish --tag="filament-peek-config"

This will add a config/filament-peek.php file to your project. Here are the main options you can configure:

Name Type Description
devicePresets array|false Quickly resize the preview iframe to specific dimensions.
initialDevicePreset string Default device preset to be activated when the preview modal is open.
showActiveDevicePreset bool Highlight the active device preset with a small circle under the icon.
allowIframeOverflow bool Allow the iframe dimensions to go beyond the capacity of the available preview modal area.
allowIframePointerEvents bool Allow all pointer events within the iframe. By default, only scrolling is allowed. (See Pointer Events)
closeModalWithEscapeKey bool Close the preview modal by pressing the Escape key.

How it Works

  • Start by adding a preview action button to the top of your page. Alternatively, you can add a preview link component somewhere in your form (e.g. in a sidebar).
  • When the button is clicked, a full-screen modal opens.
  • The modal contains an iframe that can be resized according to some configured presets.
  • The iframe can either render a full Blade view or a custom URL.

Basic Usage with Blade Views

In your EditRecord pages:

  • Add the HasPreviewModal trait.
  • Add the PreviewAction class to the returned array in getActions().
  • Override the getPreviewModalView() method to define your Blade view.
  • If your view expects a $page variable, override the getPreviewModalDataRecordKey() method to define it. By default, this variable will be $record.

The modal can also be used on CreateRecord pages and, if needed, ListRecords pages.

Complete Example

app/Filament/Resources/PageResource/Pages/EditPage.php

namespace App\Filament\Resources\PageResource\Pages;

use App\Filament\Resources\PageResource;
use Filament\Resources\Pages\EditRecord;
use Pboivin\FilamentPeek\Pages\Actions\PreviewAction;
use Pboivin\FilamentPeek\Pages\Concerns\HasPreviewModal;

class EditPage extends EditRecord
{
    use HasPreviewModal;

    protected static string $resource = PageResource::class;

    protected function getActions(): array
    {
        return [
            PreviewAction::make(),
        ];
    }

    protected function getPreviewModalView(): ?string
    {
        return 'pages.preview';
    }

    protected function getPreviewModalDataRecordKey(): ?string
    {
        return 'page';
    }
}

Detecting the Preview Modal

If you're using the same Blade view for the site page and the preview modal, you can detect if the view is currently rendered in a preview modal by checking for the $isPeekPreviewModal variable:

resources/views/pages/show.blade.php

<x-layout>
    @isset($isPeekPreviewModal)
        <x-preview-banner />
    @endisset
    
    <x-container>
        ...
    </x-container>
</x-layout>

Adding Extra Data to Previews

By default, the $record and $isPeekPreviewModal variables are made available to the rendered Blade view. If your form is relatively simple and all fields belong directly to the record, this may be all you need. However, if you have complex relationships or heavily customized form fields, you may need to include some additional data in order to render your page preview. You can add other variables by overriding the mutatePreviewModalData() method:

class EditPage extends EditRecord
{
    // ...
    
    protected function mutatePreviewModalData($data): array
    {
        $data['message'] = 'This is a preview';

        return $data;
    }
}

This would make a $message variable available to the view when rendered in the preview modal.

Inside of mutatePreviewModalData() you can access:

  • the modified record with unsaved changes: $data['record']
  • the original record: $this->record
  • any other data from the form: $this->data['my_custom_field']

Dynamically Setting the View

If needed, you can use the previewModalData property to dynamically set the modal view:

class EditPage extends EditRecord
{
    // ...
    
    protected function getPreviewModalView(): ?string
    {
        return $this->previewModalData['record']->is_featured ? 
            'posts.featured' :
            'posts.show';
    }
}

Alternate Templating Engines

If you're not using Blade views on the front-end, override the renderPreviewModalView() method and render the preview with your templating engine of choice:

    protected function renderPreviewModalView($view, $data): string
    {
        return MyTemplateEngine::render($view, $data);
    }

Using a Preview URL

Instead of rendering a view, you may implement page previews using a custom URL and the PHP session (or cache). Instead of getPreviewModalView(), override the getPreviewModalUrl() method to return the preview URL:

class EditPage extends EditRecord
{
    // ...
    
    protected function getPreviewModalUrl(): ?string
    {
        $token = uniqid();

        $sessionKey = "preview-$token";

        session()->put($sessionKey, $this->previewModalData);

        return route('pages.preview', ['token' => $token]);
    }
}

Then, you can fetch the preview data from the controller through the session (or cache):

class PageController extends Controller
{
    // ...

    public function preview($token)
    {
        $previewData = session("preview-$token");

        abort_if(is_null($previewData), 404);
        
        // ...
    }
}

This technique can also be used to implement page previews with a decoupled front-end (e.g. Next.js):

  • From getPreviewModalUrl(), generate the preview token and return a front-end preview URL.
  • Then from the front-end page component, fetch the preview data from the back-end preview URL.

Embedding a Preview Link into the Form

Instead of PreviewAction, you can use the PreviewLink component to integrate the Preview button directly in your form (e.g. in a sidebar):

use Pboivin\FilamentPeek\Forms\Components\PreviewLink;

class PageResource extends Resource
{
    // ...

    public static function form(Form $form): Form
    {
        return $form->schema([
            // ...

            PreviewLink::make(),
        ]);
    }
}

Pointer Events

By default, only scrolling is allowed in the preview iframe. This is done by inserting a very small <style> tag at the end of your preview's <body>. If this doesn't work for your use-case, you can enable all pointer events with the allowIframePointerEvents configuration.

If you need finer control over pointer events in your previews, first set this option to true. Then, in your page template, add the required CSS or JS. Here's an exemple disabling preview pointer events only for <a> tags:

resources/views/pages/show.blade.php

...

@isset($isPeekPreviewModal)
    <style>
        a { pointer-events: none !important; }
    </style>
@endisset

Testing

composer test

Changelog

Please see CHANGELOG for more information on what has changed recently.

Contributing

Please see CONTRIBUTING for details.

Security Vulnerabilities

Please review our security policy on how to report security vulnerabilities.

Credits

Acknowledgements

The initial idea is heavily inspired by module previews in Twill CMS.

License

The MIT License (MIT). Please see License File for more information.

You might also like...
My personal uptime checker powered by Filament. ⚡️

About Laravel Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experie

Manage your Sanctum tokens inside of Filament. ✨

:package_description This is where your description should go. Limit it to a paragraph or two. Consider adding a small example. Installation You can i

Ranting field for the Filament forms
Ranting field for the Filament forms

Ranting field for the Filament forms

A non-intrusive support form that can be displayed on any page
A non-intrusive support form that can be displayed on any page

A non-intrusive support bubble that can be displayed on any page Using this package you can quickly add a chat bubble that opens a support form on any

Page visit counter
Page visit counter

Cookies_php Page visit counter With using array $_COOKIE['test'] and func setcookie(name, value); The Open Server Panel was used to work with the code

Simple, modern looking server status page with administration and some nice features, that can run even on shared webhosting
Simple, modern looking server status page with administration and some nice features, that can run even on shared webhosting

Simple, modern looking server status page with administration and some nice features, that can run even on shared webhosting

Automatically delete old SiteTree page versions from Silverstripe

Version truncator for Silverstripe An extension for Silverstripe to automatically delete old versioned DataObject records from your database when a re

Silverstripe-ideannotator - Generate docblocks for DataObjects, Page, PageControllers and (Data)Extensions

silverstripe-ideannotator This module generates @property, @method and @mixin tags for DataObjects, PageControllers and (Data)Extensions, so ide's lik

Alerts users in the SilverStripe CMS when multiple people are editing the same page.

Multi-User Editing Alert Alerts users in the SilverStripe CMS when multiple people are editing the same page. Maintainer Contact Julian Seidenberg ju

Comments
  • Scrolling Not Allowed By Default

    Scrolling Not Allowed By Default

    The README states:

    By default, only scrolling is allowed in the preview iframe.

    This appears to not be the case. When allowIframePointerEvents config is set to false the iframe gets the pointer-events: none CSS property set which prevents all interaction with the iframe including scrolling.

    Tested in FireFox and Chromium.

    It appears the only way to get scrolling and nothing else is to add the pointer-events declaration to the template as described further on in the README.

    opened by freshleafmedia 3
  • Bump aglipanci/laravel-pint-action from 2.2.0 to 2.3.0

    Bump aglipanci/laravel-pint-action from 2.2.0 to 2.3.0

    Bumps aglipanci/laravel-pint-action from 2.2.0 to 2.3.0.

    Release notes

    Sourced from aglipanci/laravel-pint-action's releases.

    v2.3.0

    Commits
    • 859b17c Merge pull request #8 from likeadeckofcards/main
    • 2d7710d Add extended note to useComposer flag
    • 9594200 Add new flag for using the local project pint version
    • 1fce957 Get pint version from local composer
    • 0ac6db6 Merge pull request #7 from Nathanjms/patch-1
    • 859061e Update README.md
    • See full diff in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    opened by dependabot[bot] 1
  • Bump dependabot/fetch-metadata from 1.5.0 to 1.5.1

    Bump dependabot/fetch-metadata from 1.5.0 to 1.5.1

    Bumps dependabot/fetch-metadata from 1.5.0 to 1.5.1.

    Release notes

    Sourced from dependabot/fetch-metadata's releases.

    v1.5.1

    What's Changed

    Bugfix:

    Dep bumps that are trivial so decided to keep this a patch release:

    Internal-facing infra changes:

    Full Changelog: https://github.com/dependabot/fetch-metadata/compare/v1...v1.5.1

    Commits
    • cd6e996 v1.5.1 (#384)
    • 64bd9b8 Fix library parser to trim trailing LF (#380)
    • 0908fa1 Merge pull request #382 from dependabot/dependabot/npm_and_yarn/types/node-20...
    • 2624edc Bump @​types/node from 20.2.1 to 20.2.3
    • d1defa4 Switch to using an app token instead of a PAT (#362)
    • cb17c9e Merge pull request #379 from dependabot/dependabot/npm_and_yarn/yargs-17.7.2
    • c6f9c16 Bump yargs from 17.7.1 to 17.7.2
    • 0f53327 Merge pull request #378 from dependabot/dependabot/npm_and_yarn/eslint-depend...
    • 398ed41 Bump the eslint-dependencies group with 2 updates
    • 801acab Merge pull request #375 from dependabot/dependabot/npm_and_yarn/eslint-depend...
    • Additional commits viewable in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    opened by dependabot[bot] 1
  • Bump dependabot/fetch-metadata from 1.4.0 to 1.5.0

    Bump dependabot/fetch-metadata from 1.4.0 to 1.5.0

    Bumps dependabot/fetch-metadata from 1.4.0 to 1.5.0.

    Release notes

    Sourced from dependabot/fetch-metadata's releases.

    v1.5.0

    What's Changed

    New Features:

    Bumped Deps:

    Docs:

    Code cleanup:

    Full Changelog: https://github.com/dependabot/fetch-metadata/compare/v1...v1.5.0

    Commits
    • 28a846a v1.5.0 (#372)
    • a2a3a43 Add workflow for floating the v1 tag to the latest release (#361)
    • 6c5b8c2 Add workflow for creating release PR's (#360)
    • c40140b Stop using deprecated set-output (#370)
    • 042f8db Add a deeplink for tagging releases to the Readme (#369)
    • fd7c300 Simplify bin/bump-version (#368)
    • 9cc71e7 Merge pull request #366 from dependabot/dependabot/npm_and_yarn/nock-13.3.1
    • f29558c Bump nock from 13.3.0 to 13.3.1
    • ec762dd Merge pull request #364 from dependabot/dependabot/npm_and_yarn/types/node-20...
    • e79c5ea Bump @​types/node from 18.15.11 to 20.2.1
    • Additional commits viewable in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    opened by dependabot[bot] 1
Releases(v0.3.0)
  • v0.3.0(Jun 11, 2023)

    What's Changed

    • feat: Show active device preset in https://github.com/pboivin/filament-peek/pull/18
    • feat: Add closeModalWithEscapeKey config in https://github.com/pboivin/filament-peek/pull/19
    • refactor: Extract alpine component and version dist assets in https://github.com/pboivin/filament-peek/pull/20

    Full Changelog: https://github.com/pboivin/filament-peek/compare/v0.2.4...v0.3.0

    Source code(tar.gz)
    Source code(zip)
  • v0.2.4(Jun 10, 2023)

    What's Changed

    • fix: Handle escape key within preview modal iframe in https://github.com/pboivin/filament-peek/pull/16
    • enh: Update preview modal pointer-events CSS selector in https://github.com/pboivin/filament-peek/pull/17

    Full Changelog: https://github.com/pboivin/filament-peek/compare/v0.2.3...v0.2.4

    Source code(tar.gz)
    Source code(zip)
  • v0.2.3(Jun 5, 2023)

    What's Changed

    • fix: Replace iframe pointer-events CSS with preview modal content style block in https://github.com/pboivin/filament-peek/pull/13

    Full Changelog: https://github.com/pboivin/filament-peek/compare/v0.2.2...v0.2.3

    Source code(tar.gz)
    Source code(zip)
  • v0.2.2(May 30, 2023)

    What's Changed

    • Bump dependabot/fetch-metadata from 1.5.0 to 1.5.1 by @dependabot in https://github.com/pboivin/filament-peek/pull/9
    • Bump aglipanci/laravel-pint-action from 2.2.0 to 2.3.0 by @dependabot in https://github.com/pboivin/filament-peek/pull/10
    • enh: Extract renderPreviewModalView method by @pboivin in https://github.com/pboivin/filament-peek/pull/11

    Full Changelog: https://github.com/pboivin/filament-peek/compare/v0.2.1...v0.2.2

    Source code(tar.gz)
    Source code(zip)
  • v0.2.1(May 28, 2023)

    What's Changed

    • fix: Remove duplicated call to getPreviewModalUrl in https://github.com/pboivin/filament-peek/pull/8
    • test: Add HasPreviewModal tests in https://github.com/pboivin/filament-peek/pull/8

    Full Changelog: https://github.com/pboivin/filament-peek/compare/v0.2.0...v0.2.1

    Source code(tar.gz)
    Source code(zip)
  • v0.2.0(May 26, 2023)

    What's Changed

    • feat: Add pointer events config in https://github.com/pboivin/filament-peek/pull/4
    • feat: Add focus trap and handle escape key in https://github.com/pboivin/filament-peek/pull/5
    • fix: Handle preset rotation when using allowIframeOverflow config in https://github.com/pboivin/filament-peek/pull/6
    • enh: Change PreviewLink into form component in https://github.com/pboivin/filament-peek/pull/7

    Full Changelog: https://github.com/pboivin/filament-peek/compare/v0.1.2...v0.2.0

    Source code(tar.gz)
    Source code(zip)
  • v0.1.2(May 22, 2023)

    What's Changed

    • Support preview modal on List and Create pages by @pboivin in https://github.com/pboivin/filament-peek/pull/3

    Full Changelog: https://github.com/pboivin/filament-peek/compare/v0.1.1...v0.1.2

    Source code(tar.gz)
    Source code(zip)
  • v0.1.1(May 22, 2023)

    What's Changed

    • Bump dependabot/fetch-metadata from 1.4.0 to 1.5.0 by @dependabot in https://github.com/pboivin/filament-peek/pull/1
    • Remove unused method by @pboivin in https://github.com/pboivin/filament-peek/pull/2

    Full Changelog: https://github.com/pboivin/filament-peek/compare/v0.1...v0.1.1

    Source code(tar.gz)
    Source code(zip)
  • v0.1(May 22, 2023)

Owner
Patrick Boivin
Web developer, terminal enthusiast and Sunday morning musician
Patrick Boivin
Magento 2 Preview/Visit Catalog allows the store owner to quickly preview the catalog (product & category) pages from the admin panel.

Magento 2 Preview/Visit Catalog Overview Magento 2 Preview/Visit Catalog allows the store owner to quickly preview the catalog (product & category) pa

Raj KB 4 Sep 27, 2022
Quickly and easily preview and test your Magento 2 order confirmation page, without hacks or spending time placing new order each time

Preview Order Confirmation Page for Magento 2 For Magento 2.0.x, 2.1.x, 2.2.x and 2.3.x Styling and testing Magento's order confirmation page can be a

MagePal :: Magento Extensions 71 Aug 12, 2022
A now playing screen for the Raspberry Pi using the Last.fm API.

raspberry-pi-now-playing A now playing screen for the Raspberry Pi using the Last.fm API. This project is detailed, with photos of how I used it with

null 44 Dec 17, 2022
A plugin that teleports to world with Fancy Loading screen like WaterdogPE!

FancyTeleportScreen This is was made by Dyzer Development This plugin was allows you to teleport other world with LoadingScreen! Information This is w

Dyzer Development 1 Feb 11, 2022
A project of a Login screen made in PHP/CSS3/HTML5/JS with MySQL database integration

A project of a Login screen made in PHP/CSS3/HTML5/JS with MySQL database integration. And animations made with CSS3 and JavaScript itself! ??

Marcel Leite de Farias 2 Apr 26, 2022
🔒 a simple login screen done in php with connection to mysql

login.php What is a login system? login (derived from the English log in) or logon or signin, is the process to access a restricted computer system ma

SEBASTIAN JN 3 Aug 21, 2022
File Upload widget with multiple file selection, drag&drop support, progress bar, validation and preview images, audio and video for jQuery

File Upload widget with multiple file selection, drag&drop support, progress bar, validation and preview images, audio and video for jQuery. Supports cross-domain, chunked and resumable file uploads. Works with any server-side platform (Google App Engine, PHP, Python, Ruby on Rails, Java, etc.) that supports standard HTML form file uploads.

Sebastian Tschan 31.1k Dec 30, 2022
Nextcloud app to do preview generation

Preview Generator Nextcloud app that allows admins to pre-generate previews. The app listens to edit events and stores this information. Once a cron j

Nextcloud 343 Dec 29, 2022
This Magento extension provides a Real Full Page Caching for Magento powered by Varnish with support of Session-Based information caching (Cart, Customer Accounts, ...) via ESI includes

This Magento extension provides a Real Full Page Caching (FPC) for Magento powered by Varnish with support of Session-Based information caching (Cart, Customer Accounts, ...) via ESI includes

Hugues Alary 95 Feb 11, 2022
PHP Japanese string helper functions for converting Japanese strings from full-width to half-width and reverse. Laravel Rule for validation Japanese string only full-width or only half-width.

Japanese String Helpers PHP Japanese string helper functions for converting Japanese strings from full-width to half-width and reverse. Laravel Rule f

Deha 54 Mar 22, 2022