// Toolbar — top strip with title, undo/redo, background popover, add-node menu,
// add-note button, save/load, and screenshot.
const { useState: useStateTB, useRef: useRefTB, useEffect: useEffectTB } = React;
function Toolbar({
title, setTitle, subtitle, setSubtitle,
defaultCurrency, setDefaultCurrency,
showTitleOnCanvas, setShowTitleOnCanvas,
bgPattern, setBgPattern, bgColor, setBgColor,
showSeq, setShowSeq,
showNotes, setShowNotes,
showAnnotations, setShowAnnotations,
canUndo, canRedo, onUndo, onRedo,
onAddNode, onAddNote,
onShotMode, onSaveProject, onLoadProject, onLoadDemo, onClear,
onShowSchedule, onAutoGroupByDate, onAutoConnectByTime,
}){
const [bgOpen, setBgOpen] = useStateTB(false);
const [moreOpen, setMoreOpen] = useStateTB(false);
const [fileOpen, setFileOpen] = useStateTB(false);
const [addOpen, setAddOpen] = useStateTB(false);
const [curOpen, setCurOpen] = useStateTB(false);
const bgRef = useRefTB(null);
const moreRef = useRefTB(null);
const fileRef = useRefTB(null);
const addRef = useRefTB(null);
const curRef = useRefTB(null);
useEffectTB(()=>{
const onDoc = (e)=>{
if (bgRef.current && !bgRef.current.contains(e.target)) setBgOpen(false);
if (moreRef.current && !moreRef.current.contains(e.target)) setMoreOpen(false);
if (fileRef.current && !fileRef.current.contains(e.target)) setFileOpen(false);
if (addRef.current && !addRef.current.contains(e.target)) setAddOpen(false);
if (curRef.current && !curRef.current.contains(e.target)) setCurOpen(false);
};
document.addEventListener('mousedown', onDoc);
return ()=>document.removeEventListener('mousedown', onDoc);
},[]);
return (
setBgOpen(v=>!v)} title="背景設定">
背景
{bgOpen && (
)}
{/* (Sequence-swap toggle removed — numbering is auto-derived from
each node's arrival/departure times.) */}
{/* Currency picker — sets the symbol auto-prefixed onto bare numbers
in the cost field. Existing entries with explicit symbols are
preserved verbatim and surface as separate per-currency totals
in the SummaryBar. */}
setCurOpen(v=>!v)}
title="費用入力時に自動付与する通貨記号を選択">
{defaultCurrency || '¥'}
{curOpen && (
通貨(自動付与)
数字だけ入力すると、この記号が自動で付きます。
既に $ や € を含む費用はそのまま保持されます。
{(window.CURRENCIES || []).map(c=>(
{ setDefaultCurrency(c.symbol); setCurOpen(false); }}
style={{padding:'6px 8px', justifyContent:'flex-start'}}
title={c.label}>
{c.symbol}
{c.label}
))}
)}
{/* Schedule (工程表) view */}
工程表
{/* Add menu — picks a node type. The "+ ノード" main button defaults to a
generic pin; the chevron opens the type picker for stations / airports
/ hotels / etc. */}
{onAddNode({type:'pin'}); setAddOpen(false);}}
title="新しい地点を追加">
ノード
setAddOpen(v=>!v)}
title="種類を選んで追加" style={{marginLeft:2, padding:'7px 7px'}}>
{addOpen && (
地点タイプ
{NODE_TYPES.map(t=>(
{onAddNode({type:t.id}); setAddOpen(false);}}
title={`${t.label}を追加`}>
{t.label}
))}
{onAddNote(); setAddOpen(false);}}>
メモを追加
)}
setFileOpen(v=>!v)} title="作業ファイル">
{fileOpen && (
{onSaveProject(); setFileOpen(false);}}>
作業ファイルを保存
{onLoadProject(); setFileOpen(false);}}>
作業ファイルを開く
)}
setMoreOpen(v=>!v)} title="その他">
{moreOpen && (
時刻から自動
{onAutoConnectByTime && onAutoConnectByTime(); setMoreOpen(false);}}
title="ノードの時刻順に矢印を自動で引き直す(既存の矢印は削除)">
時刻順に自動接続
{onAutoGroupByDate && onAutoGroupByDate(); setMoreOpen(false);}}
title="各ノードの到着・出発日時から「1日目/2日目…」のグループを自動生成">
日付でグループ自動生成
サンプルを読み込む
{onLoadDemo('travel'); setMoreOpen(false);}}>
旅行(箱根 1泊2日)
{onLoadDemo('business'); setMoreOpen(false);}}>
出張(大阪 1泊2日)
{onClear(); setMoreOpen(false);}}>
すべてクリア
)}
スクショ
);
}
window.Toolbar = Toolbar;