サイドバープラグイン

サイドバープラグインは、DayFlow カレンダーにカレンダー管理サイドバーを追加します。日付ナビゲーション用のミニカレンダー、表示切替付きカレンダーリスト、カレンダーの CRUD 操作(作成、名前変更、色変更、統合、削除、インポート/エクスポート)を含みます。

インストール

プラグインパッケージをインストールします:

npm install @dayflow/plugin-sidebar
pnpm add @dayflow/plugin-sidebar
yarn add @dayflow/plugin-sidebar
bun add @dayflow/plugin-sidebar

使い方

import { useCalendarApp, DayFlowCalendar } from '@dayflow/react'; // or '@dayflow/vue', '@dayflow/svelte', '@dayflow/angular'
import { createSidebarPlugin } from '@dayflow/plugin-sidebar';

function MyCalendar() {
  const sidebarPlugin = createSidebarPlugin({
    width: 280,
    createCalendarMode: 'modal',
  });

  const calendar = useCalendarApp({
    views: [
      /* ビュー */
    ],
    plugins: [sidebarPlugin],
  });

  return <DayFlowCalendar calendar={calendar} />;
}

設定リファレンス

プロパティデフォルト説明
widthnumber | string'240px'サイドバーの幅(例: 280 または '20rem'
miniWidthstring'50px'折りたたみ時のサイドバーの幅
initialCollapsedbooleanfalseサイドバーを折りたたんだ状態で開始するかどうか
createCalendarMode'inline' | 'modal''inline'カレンダー作成フォームの表示方法
colorPickerMode'blossom' | 'default''default'使用するカラーピッカーコンポーネント
onSubscribeCalendar(calendar, events) => Promise<void>undefined新しい購読が追加された後のコールバック
onLoadSubscription(calendar) => Promise<void>undefined既存の購読用のカスタムローダー
onReorder(calendars: CalendarType[]) => void | Promise<void>undefinedカレンダーの並べ替え後のコールバック
render(props: CalendarSidebarRenderProps) => TNodeundefinedサイドバー UI を完全にオーバーライドします
renderSidebarHeader(args: SidebarHeaderSlotArgs) => TNodeundefinedカスタムサイドバーヘッダーレンダラー
renderCalendarContextMenu(calendar, onClose) => TNodeundefinedカレンダー項目のカスタムコンテキストメニューレンダラー
renderCreateCalendarDialog(props) => TNodeundefinedカスタムカレンダー作成ダイアログレンダラー

機能

サイドバープラグインは、可視状態のトグル、カレンダーの配色表示、折りたたみボタンを備えた既製のレイアウトを提供します。また、カレンダーの作成とコンテキストメニューもサポートしており、ユーザーがカレンダーの追加、色の編集、削除を自由に行うことができます。

組み込み機能:

  • ミニカレンダー - 日付の素早いナビゲーション用のコンパクトな月表示
  • カレンダーリスト - 色分けされたチェックボックスで個々のカレンダーの表示を切替
  • カレンダー作成 - カスタム名と色で新しいカレンダーを追加
  • 名前変更 / 色変更 - カレンダーを右クリックして名前や色を変更
  • カレンダーの並べ替え - リスト内でカレンダーをドラッグ&ドロップして並べ替えることができます。onReorder コールバックを使用して、新しい順序をバックエンドに保存できます。
  • カレンダー統合 - あるカレンダーの全イベントを別のカレンダーに移動
  • カレンダー削除 - 確認ステップ付きでカレンダーを削除(事前に統合も可能)
  • インポート / エクスポート - .ics ファイルのインポートまたはカレンダーを .ics にエクスポート
  • カレンダーを登録 - ICS URL でリモートの .ics フィードを登録でき、登録済みカレンダーにはサイドバーリストにバッジアイコンが表示されます

デモ

DayFlow のサイドバー体験を 2 つのデモで紹介します。標準 UI のまま使うパターンと、完全カスタムに置き換えるパターンを比較しながら確認してください。

見どころ

  • 表示の同期: 可視状態を切り替えるとカレンダー側もリアルタイムに反映
  • ドラッグ & 同期: ビューを切り替えてもカスタムサイドバーに表示する「次の予定」や KPI を同期可能
  • 折りたたみ: 集中したいときは折りたたんで表示領域を広げられる

カレンダーを登録

サイドバーにはリモート ICS カレンダーフィードを登録する機能が組み込まれています。サイドバーのカレンダーリストまたは空き領域を右クリックしてコンテキストメニューを開き、カレンダーを登録を選択し、公開されている .ics URL を入力するだけで利用できます。

DayFlow はファイルを取得してイベントを解析し、新しいカレンダーを自動的に作成します。登録済みカレンダーはサイドバーリストに小さなバッジアイコンが表示され、ローカルで作成したカレンダーと区別できます。

自動読み込みと重複排除

初期設定で subscription.url を持つカレンダーを提供すると、サイドバープラグインはマウント時に自動的に最新のイベントを取得します。

ローカルにキャッシュされたイベントと、新しく取得した購読データを組み合わせる際の二重表示を防ぐため、DayFlow はIDベースの重複排除を実装しています:

  • 購読から取得したイベントが、コアストア内の既存イベントと同じ id を持っている場合、購読側のバージョンが優先されます。
  • これにより、ページをリロードした後にイベントが「二重に」表示されることなく、常に最新の情報を UI に表示できます。

購読カレンダーの永続化

DayFlow は CalendarTypesubscription オブジェクトが存在するかどうかで購読カレンダーを識別します。

購読カレンダーのデフォルト動作:

  • 読み取り専用:タイトル編集、カレンダー変更、削除などの UI 操作が canMutateFromUI() を介して無効化されます。
  • ドラッグ不可:ドラッグ&ドロップ操作(移動、リサイズ)が無効化されます。
  • 備考の非表示:イベントに説明がない場合、詳細パネルの「備考」フィールドは非表示になり、UI が整理されます。

ユーザーに購読イベントの編集や移動を許可したい場合は、カレンダーオブジェクトに readOnly: false を設定することで、これらのデフォルトの保護を明示的に上書きできます:

const calendar = useCalendarApp({
  calendars: [
    {
      id: 'team-ics',
      name: 'チームカレンダー',
      subscription: {
        url: 'https://example.com/calendar.ics',
        status: 'ready',
      },
      // デフォルトの保護を上書き:
      readOnly: false, // UI 操作とドラッグ&ドロップの両方を有効化
      colors: {
        /* ... */
      },
    },
  ],
});

カレンダーの状態をバックエンドに保存する際は subscription フィールドを保持し、次回の読み込み時に復元してください。 }, ], });


> **注意:** DayFlow は登録済みフィードを自動更新しません。イベントを最新の状態に保つには、アプリ側で定期的な取得を実装し、`app.addEvent()` / `app.removeEvent()` でイベントを更新してください。

## 完全なカスタマイズ

独自のサイドバーコンポーネントを使用することも可能です。`createSidebarPlugin` の `render` にレンダリング関数を渡すだけで、リアルタイムのカレンダー状態とヘルパーアクションを受け取ることができます。

```tsx
import {
  createSidebarPlugin,
  type CalendarSidebarRenderProps,
} from '@dayflow/plugin-sidebar';

const CustomSidebar = ({
  app,
  calendars,
  toggleCalendarVisibility,
  toggleAll,
  isCollapsed,
  setCollapsed,
}: CalendarSidebarRenderProps) => {
  if (isCollapsed) {
    return (
      <div className='p-2'>
        <button onClick={() => setCollapsed(false)}>→</button>
      </div>
    );
  }

  return (
    <aside className='flex h-full flex-col gap-4 p-4 bg-slate-50 border-r'>
      <header className='flex items-center justify-between'>
        <h3 className='font-semibold'>マイワークスペース</h3>
        <button onClick={() => setCollapsed(true)}>←</button>
      </header>

      <nav className='space-y-1'>
        {calendars.map(calendar => (
          <label
            key={calendar.id}
            className='flex items-center gap-2 cursor-pointer'
          >
            <input
              type='checkbox'
              checked={calendar.isVisible}
              onChange={e =>
                toggleCalendarVisibility(calendar.id, e.target.checked)
              }
            />
            <span
              className='w-3 h-3 rounded-full'
              style={{ backgroundColor: calendar.colors.lineColor }}
            />
            {calendar.name}
          </label>
        ))}
      </nav>

      <div className='mt-auto pt-4 border-t text-xs text-slate-500'>
        選択日: {app.getCurrentDate().toLocaleDateString()}
      </div>
    </aside>
  );
};

const sidebarPlugin = createSidebarPlugin({
  render: props => <CustomSidebar {...props} />,
});

カスタムコンテキストメニュー

カレンダー項目のデフォルトの右クリックメニューを置き換えることができます:

createSidebarPlugin({
  renderCalendarContextMenu: (calendar, onClose) => (
    <div className='bg-white shadow-lg border rounded p-2'>
      <button
        onClick={() => {
          console.log('カスタムアクション');
          onClose();
        }}
      >
        {calendar.name} のカスタムアクション
      </button>
    </div>
  ),
});

カスタムカレンダー作成ダイアログ

デフォルトのカレンダー作成ダイアログを置き換えることができます:

createSidebarPlugin({
  renderCreateCalendarDialog: ({ onCreate, onClose }) => (
    <MyCustomDialog onSave={onCreate} onCancel={onClose} />
  ),
});

カスタムサイドバーヘッダー

デフォルトのサイドバーヘッダー(「カレンダー」というタイトルと折りたたみボタンがある領域)を置き換えることができます:

createSidebarPlugin({
  renderSidebarHeader: ({ isCollapsed, onCollapseToggle }) => (
    <div className='flex items-center justify-between p-4 border-b'>
      {!isCollapsed && (
        <span className='font-bold text-lg'>マイカレンダー</span>
      )}
      <button
        onClick={onCollapseToggle}
        className='p-1 hover:bg-slate-100 rounded'
      >
        {isCollapsed ? '→' : '←'}
      </button>
    </div>
  ),
});

On this page