サイドバープラグイン
サイドバープラグインは、DayFlow カレンダーにカレンダー管理サイドバーを追加します。日付ナビゲーション用のミニカレンダー、表示切替付きカレンダーリスト、カレンダーの CRUD 操作(作成、名前変更、色変更、統合、削除、インポート/エクスポート)を含みます。
インストール
プラグインパッケージをインストールします:
使い方
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} />;
}設定リファレンス
| プロパティ | 型 | デフォルト | 説明 |
|---|---|---|---|
width | number | string | '240px' | サイドバーの幅(例: 280 または '20rem') |
miniWidth | string | '50px' | 折りたたみ時のサイドバーの幅 |
initialCollapsed | boolean | false | サイドバーを折りたたんだ状態で開始するかどうか |
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) => TNode | undefined | サイドバー UI を完全にオーバーライドします |
renderSidebarHeader | (args: SidebarHeaderSlotArgs) => TNode | undefined | カスタムサイドバーヘッダーレンダラー |
renderCalendarContextMenu | (calendar, onClose) => TNode | undefined | カレンダー項目のカスタムコンテキストメニューレンダラー |
renderCreateCalendarDialog | (props) => TNode | undefined | カスタムカレンダー作成ダイアログレンダラー |
機能
サイドバープラグインは、可視状態のトグル、カレンダーの配色表示、折りたたみボタンを備えた既製のレイアウトを提供します。また、カレンダーの作成とコンテキストメニューもサポートしており、ユーザーがカレンダーの追加、色の編集、削除を自由に行うことができます。
組み込み機能:
- ミニカレンダー - 日付の素早いナビゲーション用のコンパクトな月表示
- カレンダーリスト - 色分けされたチェックボックスで個々のカレンダーの表示を切替
- カレンダー作成 - カスタム名と色で新しいカレンダーを追加
- 名前変更 / 色変更 - カレンダーを右クリックして名前や色を変更
- カレンダーの並べ替え - リスト内でカレンダーをドラッグ&ドロップして並べ替えることができます。
onReorderコールバックを使用して、新しい順序をバックエンドに保存できます。 - カレンダー統合 - あるカレンダーの全イベントを別のカレンダーに移動
- カレンダー削除 - 確認ステップ付きでカレンダーを削除(事前に統合も可能)
- インポート / エクスポート -
.icsファイルのインポートまたはカレンダーを.icsにエクスポート - カレンダーを登録 - ICS URL でリモートの
.icsフィードを登録でき、登録済みカレンダーにはサイドバーリストにバッジアイコンが表示されます
デモ
DayFlow のサイドバー体験を 2 つのデモで紹介します。標準 UI のまま使うパターンと、完全カスタムに置き換えるパターンを比較しながら確認してください。
見どころ
- 表示の同期: 可視状態を切り替えるとカレンダー側もリアルタイムに反映
- ドラッグ & 同期: ビューを切り替えてもカスタムサイドバーに表示する「次の予定」や KPI を同期可能
- 折りたたみ: 集中したいときは折りたたんで表示領域を広げられる
カレンダーを登録
サイドバーにはリモート ICS カレンダーフィードを登録する機能が組み込まれています。サイドバーのカレンダーリストまたは空き領域を右クリックしてコンテキストメニューを開き、カレンダーを登録を選択し、公開されている .ics URL を入力するだけで利用できます。
DayFlow はファイルを取得してイベントを解析し、新しいカレンダーを自動的に作成します。登録済みカレンダーはサイドバーリストに小さなバッジアイコンが表示され、ローカルで作成したカレンダーと区別できます。
自動読み込みと重複排除
初期設定で subscription.url を持つカレンダーを提供すると、サイドバープラグインはマウント時に自動的に最新のイベントを取得します。
ローカルにキャッシュされたイベントと、新しく取得した購読データを組み合わせる際の二重表示を防ぐため、DayFlow はIDベースの重複排除を実装しています:
- 購読から取得したイベントが、コアストア内の既存イベントと同じ
idを持っている場合、購読側のバージョンが優先されます。 - これにより、ページをリロードした後にイベントが「二重に」表示されることなく、常に最新の情報を UI に表示できます。
購読カレンダーの永続化
DayFlow は CalendarType に subscription オブジェクトが存在するかどうかで購読カレンダーを識別します。
購読カレンダーのデフォルト動作:
- 読み取り専用:タイトル編集、カレンダー変更、削除などの 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>
),
});