Zenn
Open1

laravel12 breadcrumb

モッモッ

https://packagist.org/packages/robertboes/inertia-breadcrumbs

install

laravel12では未対応。ここではローカルにダウンロードしてテストしている

$ ./vendor/bin/sail artisan vendor:publish --tag="inertia-breadcrumbs-config"

   INFO  Publishing [inertia-breadcrumbs-config] assets.

  Copying file [inertia-breadcrumbs/config/inertia-breadcrumbs.php] to [config/inertia-breadcrumbs.php] ......... DONE
config/inertia-breadcrumbs.php
<?php

use RobertBoes\InertiaBreadcrumbs\Classifier\AppendAllBreadcrumbs;
use RobertBoes\InertiaBreadcrumbs\Classifier\IgnoreSingleBreadcrumbs;
use RobertBoes\InertiaBreadcrumbs\Collectors\DiglacticBreadcrumbsCollector;
use RobertBoes\InertiaBreadcrumbs\Collectors\GretelBreadcrumbsCollector;
use RobertBoes\InertiaBreadcrumbs\Collectors\TabunaBreadcrumbsCollector;

return [
    'middleware' => [
        /**
         * ミドルウェアをこのパッケージが自動的に登録するかどうかを決定します。
         * 自分で登録したい場合は `false` に設定してください。
         */
        'enabled' => true,

        /**
         * ミドルウェアはデフォルトで 'web' グループに追加されます。
         */
        'group' => 'web',

        /**
         * 共有されるパンくずリストのキー
         */
        'key' => 'breadcrumbs',
    ],

    /**
     * デフォルトでは `diglactic/laravel-breadcrumbs` のコレクターが使用されます。
     * `tabuna/breadcrumbs` を使用する場合は `TabunaBreadcrumbsCollector::class` を指定してください。
     * `glhd/gretel` を使用する場合は `GretelBreadcrumbsCollector::class` を指定してください(このパッケージを使用する際の注意点は README を参照)。
     */
    'collector' => DiglacticBreadcrumbsCollector::class,

    /**
     * パンくずリストを Inertia のレスポンスに追加するかどうかを決定する分類器。
     * これは、他のルートが拡張できるパンくずリストを定義したが、単独のパンくずリストは表示したくない場合に便利です。
     */
    'classifier' => AppendAllBreadcrumbs::class,
    // 'classifier' => IgnoreSingleBreadcrumbs::class,

    /**
     * 現在のルートを判定する際にクエリ文字列を無視するかどうか
     */
    'ignore_query' => true,
];

diglactic/laravel-breadcrumbs のinstall

./vendor/bin/sail composer require diglactic/laravel-breadcrumbs
routes/breadcrumbs.php
<?php
use Diglactic\Breadcrumbs\Breadcrumbs;
use Diglactic\Breadcrumbs\Generator as BreadcrumbTrail;

Breadcrumbs::for('users.index', function (BreadcrumbTrail $trail) {
    $trail->push(__('Users'), route('users.index'));
});

forと合ってないといけない

使う

import TextLink from '@/components/text-link';
import { Button } from '@/components/ui/button';
import AppLayout from '@/layouts/app-layout';
import { type BreadcrumbItem, type User } from '@/types';
import { Head, Link, usePage } from '@inertiajs/react';

export default function UserIndex({ users }: { users: User[] }) {
  const { props: { flash, breadcrumbs } } = usePage();
  console.log(breadcrumbs);


  const b: BreadcrumbItem[] = [
    {
      title: 'Users',
      href: route('users.index'),
    },
  ];

  return (
    <AppLayout breadcrumbs={b}>

まあこれで確かに取れるのだが

[
    {
        "title": "Users",
        "url": "http://43.206.99.197:8000/users",
        "current": true
    }
]

型式が一致していない

そもそも

users.indexとかでいちいちこれを書きたくない

export default function UserIndex({ users }: { users: User[] }) {
  const { props: { flash } } = usePage();

  return (
    <AppLayout>

こんな感じでbreadcrumbを取り払う

resources/js/layouts/app-layout.tsx で取得する

アローを解除

import AppLayoutTemplate from '@/layouts/app/app-sidebar-layout';
import { type BreadcrumbItem } from '@/types';
import { usePage } from '@inertiajs/react';

interface AppLayoutProps {
  children: React.ReactNode;
  breadcrumbs?: BreadcrumbItem[];
}

export default function AppLayout({ children, breadcrumbs, ...props }: AppLayoutProps) {
  return (
    <AppLayoutTemplate breadcrumbs={breadcrumbs} {...props}>
      {children}
    </AppLayoutTemplate>
  );
}

usePageから取得

import AppLayoutTemplate from '@/layouts/app/app-sidebar-layout';
import { type BreadcrumbItem } from '@/types';
import { usePage } from '@inertiajs/react';

interface AppLayoutProps {
  children: React.ReactNode;
  breadcrumbs?: BreadcrumbItem[];
}

export default function AppLayout({ children, ...props }: AppLayoutProps) {
  const { props: { breadcrumbs } } = usePage();
  return (
    <AppLayoutTemplate breadcrumbs={breadcrumbs} {...props}>
      {children}
    </AppLayoutTemplate>
  );
}

変換

import AppLayoutTemplate from '@/layouts/app/app-sidebar-layout';
import { type BreadcrumbItem } from '@/types';
import { usePage } from '@inertiajs/react';

interface AppLayoutProps {
  children: React.ReactNode;
  breadcrumbs?: BreadcrumbItem[];
}

export default function AppLayout({ children, ...props }: AppLayoutProps) {
  const { props: { breadcrumbs } } = usePage();
  const formattedBreadcrumbs: BreadcrumbItem[] = breadcrumbs.map((b: any) => ({
    title: b.title,
    href: b.url,
  }));
  console.log(formattedBreadcrumbs);

  return (
    <AppLayoutTemplate breadcrumbs={breadcrumbs} {...props}>
      {children}
    </AppLayoutTemplate>
  );
}

よさそうなんで

resources/js/layouts/app-layout.tsx
import AppLayoutTemplate from '@/layouts/app/app-sidebar-layout';
import { type BreadcrumbItem } from '@/types';
import { usePage } from '@inertiajs/react';

interface AppLayoutProps {
  children: React.ReactNode;
  breadcrumbs?: BreadcrumbItem[];
}

export default function AppLayout({ children, ...props }: AppLayoutProps) {
  const { props: { breadcrumbs = [] } } = usePage();
  const formattedBreadcrumbs: BreadcrumbItem[] = breadcrumbs.map((b: any) => ({
    title: b.title,
    href: b.url,
  }));

  return (
    <AppLayoutTemplate breadcrumbs={formattedBreadcrumbs} {...props}>
      {children}
    </AppLayoutTemplate>
  );
}

既存コードのメンテ


<?php
use Diglactic\Breadcrumbs\Breadcrumbs;
use Diglactic\Breadcrumbs\Generator as BreadcrumbTrail;
use App\Models\User;

Breadcrumbs::for('dashboard', function (BreadcrumbTrail $trail) {
    $trail->push(__('Dashboard'), route('dashboard'));
});

Breadcrumbs::for('profile.edit', function (BreadcrumbTrail $trail) {
    $trail->push(__('Profile settings'), route('profile.edit'));
});
Breadcrumbs::for('password.edit', function (BreadcrumbTrail $trail) {
    $trail->push(__('Password settings'), route('password.edit'));
});
Breadcrumbs::for('appearance', function (BreadcrumbTrail $trail) {
    $trail->push(__('Appearance settings'), route('appearance'));
});

Breadcrumbs::for('users.index', function (BreadcrumbTrail $trail) {
    $trail->push(__('Users'), route('users.index'));
});
Breadcrumbs::for('users.create', function (BreadcrumbTrail $trail) {
    $trail->parent('users.index');
    $trail->push(__('Create'), route('users.create'));
});
Breadcrumbs::for('users.show', function (BreadcrumbTrail $trail, User $user) {
    $trail->parent('users.index');
    $trail->push($user->name, route('users.show', $user));
});
Breadcrumbs::for('users.edit', function (BreadcrumbTrail $trail, User $user) {
    $trail->parent('users.show', $user);
    $trail->push(__('Edit'), route('users.edit', $user));
});

こんな感じで追加していき、AppLayoutのbreadcrumbの引数を解除

リリース

ライブラリーがlaravel12に対応したら考えます

https://github.com/catatsumuri/laravel12-user-admin/tree/feature/inertia-breadcrumbs-laravel12

まあ一応branchには作業置いといたけどブツがないのでREADME.mdの通りにはlibraryはインストールできないかと

ログインするとコメントできます