flavorly/inertia-flash

快速闪现并与任何地方共享 InertiaJS 变量,持久化在会话中。

v0.6.2 2024-07-31 22:36 UTC

README

Latest Version on Packagist GitHub Tests Action Status GitHub Code Style Action Status Total Downloads

快速将变量闪现并共享到 InertiaJS,这些变量在会话或缓存中持久化。这在重定向和返回时非常有用!在任何地方与 Inertia 共享 :)

安装

您可以通过 composer 安装此包

composer require flavorly/inertia-flash

您可以使用以下命令发布配置文件

php artisan vendor:publish --tag="inertia-flash-config"

这是发布配置文件的内容

<?php
return [
    /*
    |--------------------------------------------------------------------------
    | Driver Configuration
    |--------------------------------------------------------------------------
    |
    | You can configure inertia flash to use session or cache as the driver.
    | when using the cache driver inertia flash will leverage your current
    | cache driver and attempt to save the temporary shared keys there.
    | A unique key is used to generate the unique key for each user
    |
    | Drivers: 'cache' or 'session' are supported.
    | Prefix Key : inertia_container_
    | Cache TTL : Time in seconds to store the keys in cache.
    */

    'prefix_key' => 'inertia_container_',
    'driver' => 'session',

    'session-driver' => \Flavorly\InertiaFlash\Drivers\SessionDriver::class,
    'cache-driver' => \Flavorly\InertiaFlash\Drivers\CacheDriver::class,

    'cache-ttl' => 60,

    /*
    |--------------------------------------------------------------------------
    | Persistent Keys
    |--------------------------------------------------------------------------
    |
    | Here you may configure the keys that should be persisted on the session,
    | even if they are empty they will be mapped to their primitives configured here.
    |
    */
    'persistent-keys' => [
        // 'some-key' => 'some-value',
        // 'messages => [],
    ],


    /*
    |--------------------------------------------------------------------------
    | Ignore URLs & Params
    |--------------------------------------------------------------------------
    |
    | The URls to ignore by default, because inertia runs on web middleware
    | Default For URLS: ['broadcasting/auth']
    |
    */
    'ignore_urls' => [
        'broadcasting/auth',
    ],
];

1) Inertia Share

您可以从代码的任何地方使用 Inertia Flash 辅助函数,并直接将变量共享到 InertiaJS。请注意,这些值仅在当前或下一个请求生命周期中保留,一旦共享到 Inertia,它们将被清除。您还可以使用闭包,底层将转换为 Laravel Closure Serializer(以前为 Opis)

use Flavorly\InertiaFlash\InertiaFlash;

// Resolve from container
$flash = app(\Flavorly\InertiaFlash\InertiaFlash::class);
$flash->share('foo', 'bar');

// Or using the helper
inertia_flash()->share('foo', 'bar');

// With a closure that will be serialized
inertia_flash()->share('foo', fn() => 'bar');

// With a nested closure
inertia_flash()->share('foo', ['bar' => 'foo', 'baz' => fn() => 'bar']);

// On Controllers return back()
return back()->inertia('foo', 'bar');

// return back() + Closures
return back()->inertia('foo', function () {
    return 'bar';
});

// Or the way cool way
inertia_flash()->share('foo', fn() => 'bar');

// Returning + the cool way
return back()->inertia('foo', fn() => 'bar');


// Appending Data
inertia_flash()->share('fruits', 'bananas',true);
inertia_flash()->share('fruits', 'oranges', true);

// Conditional Sharing
inertia_flash()->shareIf($foo === true, 'foo', 'bar');
inertia_flash()->shareUnless($foo === false, 'foo', 'bar');

// Appending
// You can also use append on regular share method as the third parameter
inertia_flash()->append('foo', 'bar');

// Sharing to a user
// Only available if driver is cache, otherwise session will always use the current logged user
inertia_flash()->forUser($user)->append('foo', 'bar');

2) 通知

此包还提供了一种构建无框架通知系统的简便方法,该系统可以与 Inertia 或其他框架共享

以下是一个基本用法示例

  notification()
    ->message('Thanks for your order! Your welcome on Site! ')
    ->viaInertia()
    ->dispatch();

2.1) 通知渠道

该包提供了4种不同的方式来转发通知,以下是一个快速概述

  • 通过 Inertia - 这会将通知共享到前端,导致在共享数据中注入一个属性,默认情况下它进入 "notifications",这可以更改,它将包含一个通知数组。
  • 通过数据库 - 这将使用 Laravel 通知系统将通知持久化到数据库
  • 通过广播 - 这将使用 Laravel Echo 将通知广播到前端
  • 通过邮件 - 这将使用 Laravel 邮件将通知发送给用户

请注意,您始终可以通过扩展原始通知类或提供配置中的配置来覆盖所有这些渠道和通知。请检查 config.php 以获取更多信息

2.2) 通知内容块

通常通知包含标题、消息和图标,但在某些情况下,您可能需要更多内容。我们为简单内容块提供了简单抽象。这对于对话框很有用,其中您想显示更多信息。请注意,这非常简单,任何更复杂的内容都应在前端处理

以下是一个快速示例

  notification()
    ->dialog()
    ->title('Thanks for your order!')
    ->message('Thanks for your order! Your welcome on Site! ')
    ->icon('🎉')
    ->block(fn (NotificationContentBlock $block) => $block->icon('🎉'))
    ->block(fn (NotificationContentBlock $block) => $block->title('Thanks for your order!'))
    ->block(fn (NotificationContentBlock $block) => $block->text('Your welcome on Site!'))
    ->block(fn (NotificationContentBlock $block) => $block->image('https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExeXRmMHp4N2o1bjQ2ajg0bXEyMmt5OXJrdW8zcmxqbHJ1MTNjZmdxbyZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/Cm9wKmKMUlRPvdoHgU/giphy-downsized-large.gif'))
    ->viaInertia()
    ->dispatch();

2.3) 通知图标

默认情况下,通知不包含任何图标,我们发送一个 "级别" 回来,因此您可以根据级别在前端决定如何处理图标。但您也可以传递更复杂的图标或原始图标(例如表情符号)作为通知图标。

  notification()
    ->message('Thanks for your order! Your welcome on Site! ')
    ->icon('🎉')
    ->dispatch();

2.4) 通知级别和类型

默认情况下,设置级别 info 和类型 flash。您可以通过调用流畅方法来更改此设置。不同的通知类型可以在应用程序中非常有用,而闪现通知更适合显示快速消息,对话框也可以用于显示更详细的信息。

  notification()
    ->message('Thanks for your order! Your welcome on Site!')
    ->success()
    ->dialog()
    ->dispatch();

  notification()
    ->message('Thanks for your order! Your welcome on Site!')
    ->error()
    ->toast()
    ->dispatch();

  notification()
    ->message('Thanks for your order! Your welcome on Site!')
    ->warning()
    ->flash()
    ->dispatch();

2.5) 通知高级

还有很多高级选项可以探索,因此我将在这里突出一些

  • 调用 dispatch() 通常会根据您的驱动程序将通知发送 "排队",调用 dispatchNow() 以立即发送。
  • 队列和连接可以在配置文件中配置,结构与Laravel相同。
  • 默认情况下没有启用任何频道,您可以通过链式调用viaInertia()viaDatabase()viaBroadcast()viaMail()来启用它们,或者使用配置来设置默认频道。
  • 默认情况下,当使用广播或数据库时,我们会尝试将通知解析为当前登录用户,但您始终可以使用toUser()to($notifiable)将其发送到特定用户/模型。
  • 当使用数据库通知时,会生成一个readable的URL,您可以在通知上调用readable($url)来覆盖它。
  • 您还可以使用readable()根据当前请求生成一个URL。
  • 目前存在一个问题,当与Inertia和数据库通知一起使用时,通知将被分享到前端,由于记录是在之后创建的,因此Inertia通知的ID是自动生成的。请使用监听器来更新或直接使用广播。

2.6) 前端通知实现

以下是一个使用Shadcn进行Flash通知的组件示例,支持表情符号、图标和iconify图标。

notification()
    ->title('Thanks for your order!'.time())
    ->message('Thanks for your order! Your welcome on site! '.time())
    ->icon('majesticons:add-column')
    ->dispatch();

React示例

import { useContext } from 'react'
import axios from 'axios'
import { AnimatePresence, LayoutGroup, motion } from 'framer-motion'
import { each } from 'lodash-es'
import { AlertFlash } from '@ui/alert-flash'
import { NotificationsFlashContext } from './notifications-context'
import type { AlertProps } from '@ui/design/alert'

export function NotificationsFlash(){
    const { state, api } = useContext(NotificationsFlashContext)

    if(!state || !api) {
        throw new Error('NotificationsFlash must be used within a provider')
    }
    
    const { notifications } = usePage<{ notifications: Notification.FlashNotification[] }>().props
    useEffect(
        () => {
            each(notifications, (notification: Notification.FlashNotification) => {
                api.push(notification)
            })
        },
        [notifications]
    )

    const onClose = (item: Notification.FlashNotification) => {
        if(item.readable?.enable && item.readable.url) {
            axios({
                method: item.readable.method,
                url: item.readable.url,
            }).then(() => {
                api.pull(item)
            })
            return
        }
        api.pull(item)
    }

    const convertLevelToVariant = (level: Notification.Enums.NotificationLevelEnum): AlertProps['variant'] => {
        switch(level) {
            case 'success':
                return 'green'
            case 'info':
                return 'blue'
            case 'warning':
                return 'warning'
            case 'error':
                return 'destructive'
            default:
                return 'blue'
        }
    }

    if(!state.items.length) {
        return null
    }

    return (
        <LayoutGroup>
            <div className="grid grid-cols-1 gap-y-2">
                <AnimatePresence>
                    {state.items.map((item) => (
                        <motion.div
                            animate={{ opacity: 1, scale: 1 }}
                            exit={{ opacity: 0, scale: 0.9 }}
                            initial={{ opacity: 0, scale: 0.9 }}
                            key={item.id}
                            transition={{ duration: 0.3, easing: 'ease-in-out' }}
                        >
                            { item.shown ? (
                                <AlertFlash
                                    closable
                                    icon={item.icon?.content}
                                    iconProps={item.icon?.props as any}
                                    text={item.message}
                                    title={item.title}
                                    variant={convertLevelToVariant(item.level)}
                                    onClose={() => { onClose(item) }}
                                />
                            ) : null }
                        </motion.div>
                    ))}
                </AnimatePresence>
            </div>
        </LayoutGroup>
    )
}

Inertia Flash的用途是什么?

此包旨在与InertiaJS框架一起使用。Inertia提供了一种很好的方式来共享变量,但有时您可能希望从代码的另一个地方共享数据。

一些用例

  • 在重定向之前共享数据(例如,back()->with('foo','bar')可以用back()->inertia('foo','bar')来复制)
  • 从控制器到视图共享数据而不使用Inertia::share()
  • 直接从服务共享数据
  • 在服务请求/页面之前从代码的任何位置共享数据
  • 从命令/作业到特定用户共享数据
  • 避免通过共享会话变量在Inertia中间件之间污染。
  • 等等。

如果您正在寻找实时共享,这个包可能不是最佳选择,建议使用Laravel Echo与Pusher或Soketi一起使用。

测试

composer test

安全漏洞

请查看我们的安全策略了解如何报告安全漏洞。

致谢

许可

MIT许可(MIT)。请参阅许可文件以获取更多信息。