-
结构
-
+ return
;
}
export function XmindSheetBar({
- outlineOpen,
- onToggleOutline,
- activeSheetId,
- formatPanelOpen,
- onAddSheet,
- onDeleteSheet,
- onDuplicateSheet,
- onFit,
- onRenameSheet,
- onSwitchSheet,
- onZoomIn,
- onZoomOut,
- sheets,
- zoomPercent,
+ outlineOpen, onToggleOutline, activeSheetId, formatPanelOpen, onAddSheet,
+ onDeleteSheet, onDuplicateSheet, onFit, onRenameSheet, onSwitchSheet,
+ onZoomIn, onZoomOut, onZoomTo, sheets, zoomPercent, topicCount, selectedCount,
}: {
outlineOpen: boolean;
onToggleOutline: () => void;
@@ -945,140 +414,45 @@ export function XmindSheetBar({
onSwitchSheet: (id: string) => void;
onZoomIn: () => void;
onZoomOut: () => void;
+ onZoomTo: (value: number) => void;
sheets: FlowBoardSheetTab[];
zoomPercent: number;
+ topicCount: number;
+ selectedCount: number;
}) {
const [renamingSheetId, setRenamingSheetId] = useState
(null);
const [renameDraft, setRenameDraft] = useState("");
- const activeSheet = sheets.find((sheet) => sheet.id === activeSheetId);
-
- const commitRename = () => {
- if (!renamingSheetId) {
- return;
- }
- const nextTitle = renameDraft.trim();
- if (nextTitle) {
- onRenameSheet(renamingSheetId, nextTitle);
- }
- setRenamingSheetId(null);
- setRenameDraft("");
- };
-
- return (
-
- );
+ const [contextId, setContextId] = useState(null);
+ const activeSheet = sheets.find(sheet => sheet.id === activeSheetId);
+ const rename = (id: string) => { const sheet = sheets.find(item => item.id === id); if (sheet) { setRenamingSheetId(id); setRenameDraft(sheet.title); } };
+ const commitRename = () => { if (renamingSheetId && renameDraft.trim()) onRenameSheet(renamingSheetId,renameDraft.trim()); setRenamingSheetId(null); };
+ return ;
}
diff --git a/components/flow-board/xmind-native.css b/components/flow-board/xmind-native.css
new file mode 100644
index 000000000..b3a62f294
--- /dev/null
+++ b/components/flow-board/xmind-native.css
@@ -0,0 +1,161 @@
+/* Xmind editing controls use the project's home/canvas typography and density. */
+.xmind-workspace {
+ --xmind-panel-width: 240px;
+ --xmind-ink: #24282b;
+ --xmind-muted: #888b8e;
+ --xmind-panel: #f3f4f5;
+ --xmind-border: #e3e5e8;
+ color: var(--xmind-ink);
+ font-family: Arial, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
+ -webkit-font-smoothing: antialiased;
+ background: white;
+ font-size: 13px;
+}
+.xmind-workspace button { cursor: pointer; }
+.xmind-workspace :is(button,input,textarea,select) { font-family: inherit; }
+.xmind-workspace button:disabled { cursor: default; opacity: .3; }
+.xmind-workspace button:focus-visible { outline: 2px solid #35b5ff; outline-offset: 2px; }
+.xmind-topbar { position:absolute; top:0; left:0; right:var(--xmind-panel-offset,0px); height:56px; z-index:50; display:flex; align-items:flex-start; padding:12px 12px 0; gap:8px; pointer-events:none; }
+.xmind-topbar > * { pointer-events:auto; }
+.xmind-document-heading { display:flex; align-items:center; gap:8px; min-width:200px; }
+.xmind-home-button { display:grid; place-items:center; width:32px; height:32px; border:1px solid var(--xmind-border); border-radius:8px; background:rgba(255,255,255,.95); box-shadow:0 2px 8px #00000006; flex-shrink:0; }
+.xmind-document-name { height:32px; display:flex; flex-direction:column; justify-content:center; gap:0; min-width:100px; }
+.xmind-document-name input { background:transparent; border:1px solid transparent; border-radius:5px; font-size:13px; font-weight:600; width:140px; padding:0 3px; outline:none; }
+.xmind-document-name input:focus { border-color:#35b5ff; }
+.xmind-document-name span { font-size:11px; padding-left:4px; }
+.xmind-document-menu { margin-left:-8px; opacity:0; transition:opacity .15s; }
+.xmind-document-heading:hover .xmind-document-menu,.xmind-document-heading:focus-within .xmind-document-menu { opacity:1; }
+.xmind-pointer-toolbar { position:absolute; top:64px; left:12px; display:flex; flex-direction:column; gap:2px; padding:3px; border:1px solid var(--xmind-border); border-radius:10px; background:#fffffff5; box-shadow:0 2px 8px #00000008; }
+.xmind-pointer-toolbar .xmind-icon-button { width:28px; height:28px; }
+.xmind-primary-tools { display:flex; align-items:center; gap:8px; margin:auto; margin-top:0; }
+.xmind-toolbar-pill { display:flex; align-items:center; padding:2px; border:1px solid var(--xmind-border); border-radius:8px; background:rgba(255,255,255,.95); box-shadow:0 2px 8px #00000006; backdrop-filter:blur(24px); }
+.xmind-icon-button { width:30px; height:28px; display:grid; place-items:center; border-radius:6px; color:var(--xmind-ink); background:transparent; flex-shrink:0; }
+.xmind-icon-button > svg { width:18px; height:18px; }
+.xmind-icon-button:hover:not(:disabled),.xmind-home-button:hover,.xmind-menu-trigger:hover { background:#00000009; }
+.xmind-icon-button.is-active { background:#363b3e; color:white; }
+.xmind-utility-tools { display:flex; align-items:center; gap:8px; }
+.xmind-menu-host { position:relative; }
+.xmind-menu-trigger { display:flex; align-items:center; justify-content:center; gap:4px; min-height:28px; padding:2px 5px; border-radius:24px; }
+.xmind-document-menu .xmind-menu-trigger > svg:last-child,.xmind-sheet-actions .xmind-menu-trigger > svg:last-child { display:none; }
+.xmind-command-menu { position:absolute; top:calc(100% + 10px); left:0; min-width:220px; max-height:min(70vh,540px); overflow-y:auto; padding:5px; border:1px solid #dedfe2; border-radius:10px; background:#fcfcfcf5; backdrop-filter:blur(24px); box-shadow:0 12px 32px #00000020,0 2px 6px #0000000a; z-index:70; }
+.xmind-menu-right { left:auto; right:0; }
+.xmind-command { width:100%; display:flex; align-items:center; gap:10px; border-radius:5px; padding:7px 9px; text-align:left; min-height:32px; color:#34393c; font-size:13px; }
+.xmind-command:hover:not(:disabled),.xmind-command:focus-visible { background:#35a6fc; color:white; outline:none; }
+.xmind-command kbd { font:inherit; opacity:.5; margin-left:auto; font-size:11px; }
+.xmind-command-check { display:block; width:16px; }
+.xmind-menu-separator { height:1px; background:#e1e2e4; margin:4px 6px; }
+.xmind-format-panel { position:absolute; top:8px; right:8px; bottom:8px; width:var(--xmind-panel-width); border-radius:12px; background:var(--xmind-panel); border:1px solid #e5e7e9; box-shadow:-5px 0 20px #00000005; display:flex; flex-direction:column; z-index:35; overflow:hidden; }
+.xmind-panel-heading { display:flex; justify-content:space-between; align-items:center; min-height:36px; padding:0 12px; font-weight:600; }
+.xmind-panel-heading button { border-radius:6px; padding:4px; color:#7a7e83; }
+.xmind-panel-heading button:hover { background:#e2e4e6; }
+.xmind-panel-tabs { display:flex; margin:4px 10px 10px; padding:3px; height:28px; border-radius:8px; background:#e7e8eb; flex-shrink:0; }
+.xmind-panel-tabs button { flex:1; border-radius:6px; font-size:12px; color:#6d7276; }
+.xmind-panel-tabs button[aria-selected=true] { background:#ffffffd9; color:#23282b; font-weight:600; }
+.xmind-panel-content { overflow-y:auto; min-height:0; padding:0 12px 12px; scrollbar-width:thin; scrollbar-color:#b5b5b5 transparent; }
+.xmind-topic-preview { min-height:48px; border:1px solid var(--xmind-border); border-radius:8px; background:#fff; display:flex; align-items:center; gap:8px; padding:8px; margin-bottom:12px; }
+.xmind-topic-preview > span { flex:1; text-align:center; font-size:14px; padding:5px; }
+.xmind-topic-preview svg { color:#5c6267; flex-shrink:0; }
+.xmind-format-section { padding:12px 0; border-top:1px solid var(--xmind-border); }
+.xmind-format-section h3 { display:flex; align-items:center; gap:5px; margin:0 0 10px; font-size:12px; font-weight:600; }
+.xmind-setting-row { display:flex; align-items:center; justify-content:space-between; gap:8px; margin:8px 0; font-size:12px; }
+.xmind-setting-row h3 { margin:0; }
+.xmind-setting-row > span { flex-shrink:0; }
+.xmind-setting-row select { height:25px; background:#fff; border:1px solid var(--xmind-border); border-radius:8px; min-width:74px; max-width:170px; padding:0 8px; font-size:12px; }
+.xmind-color-control { height:25px; width:74px; padding:0; border:1px solid var(--xmind-border); border-radius:8px; overflow:hidden; background:white; cursor:pointer; }
+.xmind-color-control::-webkit-color-swatch-wrapper { padding:0; }
+.xmind-color-control::-webkit-color-swatch { border:0; border-radius:7px; }
+.xmind-segmented { display:flex; border:1px solid var(--xmind-border); background:white; border-radius:8px; overflow:hidden; height:27px; }
+.xmind-segmented button { flex:1; display:grid; place-items:center; margin:2px; border-radius:6px; }
+.xmind-segmented button[aria-pressed=true] { background:#e4e6e8; }
+.xmind-segmented button:hover:not(:disabled) { background:#f1f2f3; }
+.xmind-shape-rectangle { width:18px; height:12px; border:1.5px solid currentColor; border-radius:3px; }
+.xmind-shape-line { width:24px; border-bottom:1.5px solid currentColor; }
+.xmind-text-marks { height:28px; margin-top:12px; }
+.xmind-structure-trigger { display:flex; height:26px; align-items:center; padding:0 8px; background:white; border:1px solid var(--xmind-border); border-radius:8px; }
+.xmind-structure-trigger svg[data-layout-preview] { width:35px; height:24px; }
+.xmind-current-structure { padding:4px 10px; margin-top:14px; border:1px solid var(--xmind-border); border-radius:8px; background:#fff; font-size:12px; color:#7e8388; }
+.xmind-structure-grid { display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:6px; margin-top:12px; }
+.xmind-structure-grid button { display:flex; flex-direction:column; justify-content:center; align-items:center; gap:4px; min-height:64px; border:1px solid #e0e3e7; border-radius:7px; font-size:9px; padding:4px 2px; background:white; }
+.xmind-structure-grid button[aria-pressed=true] { border-color:#36b4ff; background:#edf8ff; color:#179cdc; }
+.xmind-background-presets { display:grid; grid-template-columns:repeat(6,1fr); gap:6px; }
+.xmind-background-presets button { height:28px; border:1px solid #d6d8dc; border-radius:6px; }
+.xmind-background-presets button[aria-pressed=true] { outline:2px solid #35b5ff; }
+.xmind-theme-grid { display:grid; grid-template-columns:repeat(3,1fr); gap:8px; }
+.xmind-theme-grid button { background:white; border:1px solid #e1e3e6; border-radius:8px; font-size:11px; padding:8px; }
+.xmind-theme-grid button[aria-pressed=true] { border-color:#35b5ff; }
+.xmind-theme-grid button > span { display:flex; margin-bottom:8px; height:12px; overflow:hidden; border-radius:3px; }
+.xmind-theme-grid i { flex:1; }
+.xmind-switch { width:30px; height:18px; border-radius:12px; background:#bfc3c8; position:relative; }
+.xmind-switch i { position:absolute; top:2px; left:2px; height:14px; width:14px; background:white; border-radius:50%; transition:transform .15s; }
+.xmind-switch[aria-checked=true] { background:#35b5ff; }
+.xmind-switch[aria-checked=true] i { transform:translateX(12px); }
+.xmind-canvas-preview { height:96px; border:1px solid var(--xmind-border); border-radius:8px; margin-top:12px; }
+.xmind-sheetbar { position:absolute; bottom:10px; left:16px; right:calc(var(--xmind-panel-offset,0px) + 16px); height:30px; z-index:40; display:flex; align-items:center; gap:8px; pointer-events:none; }
+.xmind-sheetbar > * { pointer-events:auto; }
+.xmind-sheet-tabs { display:flex; gap:4px; max-width:60%; overflow-x:auto; scrollbar-width:none; }
+.xmind-sheet-tab-host { flex-shrink:0; }
+.xmind-sheet-tab-host > button { border-radius:16px; padding:4px 18px; font-size:12px; font-weight:500; background:#ffffffd9; max-width:180px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
+.xmind-sheet-tab-host > button[aria-pressed=true] { background:#e4e5e6; font-weight:600; }
+.xmind-sheet-tab-host input { width:130px; height:25px; border-radius:6px; background:white; border:1px solid #35b5ff; padding:0 8px; }
+.xmind-sheet-context { position:absolute; bottom:36px; min-width:140px; padding:5px; border:1px solid #e2e4e7; border-radius:10px; background:white; box-shadow:0 10px 25px #00000015; }
+.xmind-sheet-context button { display:block; width:100%; text-align:left; padding:7px 10px; border-radius:6px; }
+.xmind-sheet-context button:hover { background:#f0f3f5; }
+.xmind-footer-divider { width:1px; height:13px; background:#dfe2e5; flex-shrink:0; }
+.xmind-footer-icon { display:grid; place-items:center; width:26px; height:26px; border-radius:6px; }
+.xmind-footer-icon:hover { background:#f2f3f5; }
+.xmind-sheet-actions { opacity:0; }
+.xmind-sheetbar:hover .xmind-sheet-actions,.xmind-sheet-actions:focus-within { opacity:1; }
+.xmind-sheet-status { margin-left:auto; display:flex; gap:12px; align-items:center; background:#ffffffd9; }
+.xmind-topic-count { font-size:11px; white-space:nowrap; }
+.xmind-zoom-menu .xmind-command-menu,.xmind-sheet-actions .xmind-command-menu { top:auto; bottom:calc(100% + 8px); }
+.xmind-zoom-menu .xmind-menu-trigger { font-size:12px; padding:0; min-width:50px; }
+.xmind-outline-toggle { font-weight:600; font-size:13px; white-space:nowrap; }
+.xmind-workspace .flow-board-canvas-shell { top:0; bottom:0; right:var(--xmind-panel-offset,0px); }
+.xmind-workspace .board-host-svg { background:transparent !important; }
+.xmind-workspace .board-active-svg { z-index:2; pointer-events:none; }
+.xmind-workspace .active-host-g path[stroke="#6698FF"] { stroke:#387cff; stroke-width:2px; vector-effect:non-scaling-stroke; }
+.xmind-workspace .active-host-g path[fill="#6698FF25"] { fill:rgba(56,124,255,.12); }
+.xmind-outline-shell { position:absolute; inset:56px var(--xmind-panel-offset,0px) 48px 0; z-index:20; }
+.xmind-workspace .xmind-aux-panel { top:8px; bottom:8px; right:8px; width:var(--xmind-panel-width); max-width:var(--xmind-panel-width); border-radius:12px; border:1px solid var(--xmind-border); background:var(--xmind-panel); }
+.xmind-zen-exit { position:absolute; top:16px; right:16px; z-index:45; display:flex; gap:8px; align-items:center; padding:9px 14px; border-radius:24px; background:#fffffff0; box-shadow:0 4px 20px #0000000c; font-size:12px; }
+.xmind-empty-canvas { position:absolute; top:50%; left:50%; transform:translate(-50%,-50%); z-index:20; border:1px solid #333; background:white; border-radius:8px; padding:8px 16px; font-size:16px; font-weight:600; }
+.xmind-search-panel { position:absolute; top:64px; left:8px; bottom:48px; width:var(--xmind-panel-width); border-radius:12px; background:var(--xmind-panel); border:1px solid var(--xmind-border); z-index:45; display:flex; flex-direction:column; box-shadow:5px 0 20px #00000008; }
+.xmind-workspace:has(.xmind-search-panel) .xmind-pointer-toolbar { visibility:hidden; }
+.xmind-search-panel .xmind-panel-content { padding:0 14px 14px; }
+.xmind-search-box { display:flex; gap:8px; border-radius:8px; border:1px solid var(--xmind-border); background:white; padding:8px; align-items:center; margin:8px 0; }
+.xmind-search-box input { outline:0; width:100%; background:transparent; font-size:13px; }
+.xmind-search-options { display:flex; align-items:center; gap:12px; margin:10px 0; font-size:11px; }
+.xmind-search-panel select { width:100%; height:30px; border-radius:8px; background:white; border:1px solid var(--xmind-border); padding:0 8px; font-size:12px; }
+.xmind-search-navigation { display:flex; align-items:center; gap:8px; margin:12px 0; font-size:11px; color:#81868b; }
+.xmind-search-navigation span { flex:1; }
+.xmind-search-navigation button { padding:4px; border-radius:5px; }
+.xmind-search-navigation button:hover { background:#e5e7e9; }
+.xmind-search-result { display:block; width:100%; text-align:left; padding:10px; border-radius:8px; margin:4px 0; background:#ffffffa6; }
+.xmind-search-result.is-active { outline:1px solid #35b5ff; background:#ecf8ff; }
+.xmind-search-result > span { display:block; font-size:13px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
+.xmind-search-result small { font-size:10px; color:#8a8e91; }
+.xmind-search-replace-buttons { display:flex; gap:8px; margin:10px 0 16px; }
+.xmind-search-replace-buttons button { flex:1; border:1px solid var(--xmind-border); border-radius:6px; background:white; padding:5px; font-size:11px; }
+.xmind-presentation { position:absolute; inset:0; z-index:60; background:#fff; display:flex; flex-direction:column; }
+.xmind-presentation > header { display:flex; align-items:center; justify-content:space-between; padding:20px 28px; color:#8b9095; font-size:12px; }
+.xmind-presentation > header button { display:flex; align-items:center; gap:6px; }
+.xmind-presentation-slide { display:flex; flex:1; flex-direction:column; align-items:center; justify-content:center; padding:60px; overflow:auto; }
+.xmind-presentation-slide h1 { font-size:clamp(28px,4vw,56px); font-weight:650; text-align:center; }
+.xmind-presentation-slide ul { display:flex; flex-direction:column; gap:20px; margin-top:40px; font-size:clamp(18px,2vw,28px); }
+.xmind-presentation-slide li { display:flex; align-items:center; gap:15px; }
+.xmind-presentation-slide li::before { content:""; width:8px; height:8px; border-radius:50%; background:#ff7160; }
+.xmind-presentation > footer { display:flex; justify-content:center; align-items:center; gap:20px; padding:20px; font-size:12px; color:#72787e; }
+.xmind-presentation > footer button { padding:8px; border:1px solid #e6e7e9; border-radius:50%; }
+@media (max-width:1100px) { .xmind-window-dots { display:none; } .xmind-document-heading { min-width:160px; gap:8px; } .xmind-document-name input { width:100px; } .xmind-utility-tools { gap:8px; } .xmind-primary-tools { gap:8px; } .xmind-topbar { gap:8px; padding-left:12px; } }
+@media (max-width:850px) { .xmind-document-name { display:none; } .xmind-document-heading { min-width:auto; } .xmind-document-menu { opacity:1; } .xmind-utility-tools > .xmind-toolbar-pill:nth-child(2) { display:none; } .xmind-topbar { justify-content:space-between; } }
+@media (max-width:640px) { .xmind-workspace { --xmind-panel-offset:0px !important; } .xmind-format-panel,.xmind-workspace .xmind-aux-panel { width:min(var(--xmind-panel-width),calc(100vw - 16px)); } .xmind-topbar { gap:4px; padding:12px 8px; } .xmind-home-button { width:32px; } .xmind-primary-tools { gap:4px; margin:0 auto; } .xmind-icon-button { width:28px; } .xmind-document-menu { display:none; } .xmind-topic-count { display:none; } .xmind-sheetbar { left:10px; right:10px; gap:5px; } .xmind-sheet-status { gap:6px; } .xmind-sheet-tabs { max-width:50%; } }
+@font-face { font-family:NeverMind; src:url('/fonts/xmind/NeverMind-Regular.ttf') format('truetype'); font-weight:400; font-style:normal; font-display:swap; }
+@font-face { font-family:NeverMind; src:url('/fonts/xmind/NeverMind-Medium.ttf') format('truetype'); font-weight:500; font-style:normal; font-display:swap; }
+@font-face { font-family:NeverMind; src:url('/fonts/xmind/NeverMind-Bold.ttf') format('truetype'); font-weight:700; font-style:normal; font-display:swap; }
+@font-face { font-family:NeverMind; src:url('/fonts/xmind/NeverMind-Extrabold.ttf') format('truetype'); font-weight:800; font-style:normal; font-display:swap; }
+@layer base {
+ .xmind-workspace .drawnix,.xmind-workspace .drawnix * { --ui-font:Arial,"PingFang SC",sans-serif; font-family:Arial,"PingFang SC",sans-serif !important; }
+ .xmind-workspace .drawnix .plait-text-container,.xmind-workspace .drawnix .plait-text-container * { font-family:NeverMind,Arial,"PingFang SC",sans-serif !important; }
+}
+
+.xmind-native-icon { display:block; width:18px; height:18px; background:currentColor; mask-size:contain; mask-position:center; mask-repeat:no-repeat; }
diff --git a/components/flow-board/xmind-presentation.tsx b/components/flow-board/xmind-presentation.tsx
new file mode 100644
index 000000000..3245d4b17
--- /dev/null
+++ b/components/flow-board/xmind-presentation.tsx
@@ -0,0 +1,28 @@
+"use client";
+
+import { ChevronLeft, ChevronRight, X } from "lucide-react";
+import { useEffect, useState } from "react";
+import type { PlaitElement } from "@plait/core";
+import { getTopicEntries, getTopicTitle } from "@/lib/flow-board/topic-details";
+
+export function XmindPresentation({ elements, title, onClose }: { elements: PlaitElement[]; title: string; onClose: () => void }) {
+ const slides = getTopicEntries(elements).filter(({ element, depth }) => depth === 0 || element.children?.length);
+ const [index,setIndex] = useState(0);
+ const entry = slides[Math.min(index,slides.length - 1)];
+ const next = () => setIndex(value => Math.min(slides.length - 1,value + 1));
+ const previous = () => setIndex(value => Math.max(0,value - 1));
+ useEffect(() => {
+ const onKey = (event: KeyboardEvent) => {
+ if (event.key === "Escape") { event.preventDefault(); onClose(); }
+ if (["ArrowRight","ArrowDown"," ","PageDown"].includes(event.key)) { event.preventDefault(); next(); }
+ if (["ArrowLeft","ArrowUp","PageUp"].includes(event.key)) { event.preventDefault(); previous(); }
+ };
+ window.addEventListener("keydown",onKey);
+ return () => window.removeEventListener("keydown",onKey);
+ }, [onClose,slides.length]);
+ return
+
+ {entry?.title || title}
{(entry?.element.children || []).map(child => - {getTopicTitle(child)}
)}
+
+ ;
+}
diff --git a/components/flow-board/xmind-search-panel.tsx b/components/flow-board/xmind-search-panel.tsx
new file mode 100644
index 000000000..cd0de0c69
--- /dev/null
+++ b/components/flow-board/xmind-search-panel.tsx
@@ -0,0 +1,45 @@
+"use client";
+
+import { ChevronDown, ChevronUp, Search, X } from "lucide-react";
+import { useEffect, useRef, useState } from "react";
+import { searchTopics, type SearchSheet, type TopicSearchResult } from "@/lib/flow-board/topic-search";
+
+export function XmindSearchPanel({ sheets, activeSheetId, onJump, onReplace, onClose }: {
+ sheets: SearchSheet[];
+ activeSheetId: string;
+ onJump: (result: TopicSearchResult) => void;
+ onReplace: (results: TopicSearchResult[], query: string, replacement: string, caseSensitive: boolean) => void;
+ onClose: () => void;
+}) {
+ const [query, setQuery] = useState("");
+ const [replacement, setReplacement] = useState("");
+ const [caseSensitive, setCaseSensitive] = useState(false);
+ const [scope, setScope] = useState("current");
+ const [activeIndex, setActiveIndex] = useState(0);
+ const input = useRef(null);
+ const results = searchTopics(scope === "all" ? sheets : sheets.filter(sheet => sheet.id === activeSheetId),query,caseSensitive);
+ useEffect(() => { input.current?.focus(); }, []);
+ useEffect(() => { setActiveIndex(0); }, [query,caseSensitive,scope]);
+ const navigate = (step: number) => {
+ if (!results.length) return;
+ const next = (Math.min(activeIndex,results.length - 1) + step + results.length) % results.length;
+ setActiveIndex(next); onJump(results[next]);
+ };
+ return ;
+}
diff --git a/components/flow-board/xmind-topic-panel.tsx b/components/flow-board/xmind-topic-panel.tsx
index a8fc7b8d3..5ae6916c3 100644
--- a/components/flow-board/xmind-topic-panel.tsx
+++ b/components/flow-board/xmind-topic-panel.tsx
@@ -96,7 +96,7 @@ export function XmindTopicPanel({
};
return (