From 788a61fa120695ffa2df6a3106dcfa71a2fa3a2c Mon Sep 17 00:00:00 2001 From: Daniel1464 Date: Sun, 7 Jun 2026 01:43:07 -0400 Subject: [PATCH 1/3] first pass --- src/components/sidebar/PathSelector.tsx | 15 ++- src/components/sidebar/Sidebar.module.css | 16 ++++ src/components/sidebar/Sidebar.tsx | 112 +++++++++++++++++++--- src/document/UIStateStore.tsx | 9 +- 4 files changed, 134 insertions(+), 18 deletions(-) diff --git a/src/components/sidebar/PathSelector.tsx b/src/components/sidebar/PathSelector.tsx index fd05f21faa..ed123a2fc0 100644 --- a/src/components/sidebar/PathSelector.tsx +++ b/src/components/sidebar/PathSelector.tsx @@ -20,8 +20,9 @@ import { SavingState } from "../../document/UIStateStore"; import SaveInProgress from "../../assets/SaveInProgress"; import { NameIssue } from "../../document/path/NameIsIdentifier"; -type Props = object; - +type Props = { + searchQuery: string; +}; type State = object; type OptionProps = { uuid: string; selected: boolean }; @@ -311,15 +312,19 @@ class PathSelectorOption extends Component { } class PathSelector extends Component { - state = {}; - Option = observer(PathSelectorOption); render() { const activePath = doc.pathlist.activePathUUID; + const filteredPathEntries = Array.from(doc.pathlist.paths.entries()) + .filter(([, path]) => + path.name.toLowerCase().includes(this.props.searchQuery.toLowerCase().trim()) + ); + // .sort((a, b) => a[1].name.localeCompare(b[1].name)); + return (
- {Array.from(doc.pathlist.paths.keys()).map((uuid) => ( + {filteredPathEntries.map(([uuid]) => ( { + render() { + const { trajSearchQuery, setTrajSearchQuery } = uiState; + + return ( +
+ setTrajSearchQuery(e.target.value)} + fullWidth + slotProps={{ + input: { + startAdornment: ( + + ), + endAdornment: trajSearchQuery && ( + setTrajSearchQuery("")} + sx={{ padding: 0 }} + > + + + ), + style: { + color: "white", + backgroundColor: "var(--background-light-gray)", + borderRadius: "4px", + height: "32px", + fontSize: "14px" + } + } + }} + sx={{ + "& .MuiOutlinedInput-notchedOutline": { + borderColor: "transparent" + }, + "&:hover .MuiOutlinedInput-notchedOutline": { + borderColor: "var(--divider-gray)" + }, + "&.Mui-focused .MuiOutlinedInput-notchedOutline": { + borderColor: "var(--accent-purple)" + } + }} + /> +
+ ); + } +} + class Sidebar extends Component { state = {}; constructor(props: Props) { super(props); } + startResize = (e: React.MouseEvent) => { + e.preventDefault(); + document.addEventListener("mousemove", this.resize); + document.addEventListener("mouseup", this.stopResize); + }; + + resize = (e: MouseEvent) => { + const newWidth = Math.max(260, Math.min(560, e.clientX)); + document.documentElement.style.setProperty("--sidebar-width", `${newWidth}px`); + }; + + stopResize = () => { + document.removeEventListener("mousemove", this.resize); + document.removeEventListener("mouseup", this.stopResize); + }; + + componentWillUnmount() { + this.stopResize(); + } + render() { - const { toggleMainMenu } = uiState; + const { toggleMainMenu, trajSearchQuery } = uiState; return (
+
{ > - { - toggleMainMenu(); - }} - > + @@ -155,12 +243,14 @@ class Sidebar extends Component {
- + + +
- +
FEATURES
diff --git a/src/document/UIStateStore.tsx b/src/document/UIStateStore.tsx index 19ada92b31..f32621ed61 100644 --- a/src/document/UIStateStore.tsx +++ b/src/document/UIStateStore.tsx @@ -67,7 +67,9 @@ export const UIStateStore = types contextMenuSelectedWaypoint: types.maybe(types.number), contextMenuWaypointType: types.maybe(types.number), - contextMenuMouseSelection: types.maybe(types.array(types.number)) // [clientX, clientY] from `MouseEvent` + contextMenuMouseSelection: types.maybe(types.array(types.number)), // [clientX, clientY] from `MouseEvent` + + trajSearchQuery: types.maybe(types.string), }) .views((self: any) => { return { @@ -210,6 +212,9 @@ export const UIStateStore = types self.contextMenuMouseSelection = mouseSelection ? [mouseSelection.clientX, mouseSelection.clientY] : undefined; - } + }, + setTrajSearchQuery(query: string) { + self.trajSearchQuery = query; + }, })); export type IUIStateStore = Instance; From 7f68e9bf994767eb3fca4aa670df97cca62e4269 Mon Sep 17 00:00:00 2001 From: Daniel1464 Date: Sun, 7 Jun 2026 10:18:15 -0400 Subject: [PATCH 2/3] second pass, seems to work --- src/components/sidebar/PathSelector.tsx | 26 ++++++-- src/components/sidebar/Sidebar.tsx | 80 ++++++++++++++++++++----- src/document/UIStateStore.tsx | 8 +++ 3 files changed, 96 insertions(+), 18 deletions(-) diff --git a/src/components/sidebar/PathSelector.tsx b/src/components/sidebar/PathSelector.tsx index ed123a2fc0..76171a9dbf 100644 --- a/src/components/sidebar/PathSelector.tsx +++ b/src/components/sidebar/PathSelector.tsx @@ -22,6 +22,8 @@ import { NameIssue } from "../../document/path/NameIsIdentifier"; type Props = { searchQuery: string; + regexMode: boolean; + sortAlphabetical: boolean; }; type State = object; @@ -314,12 +316,28 @@ class PathSelectorOption extends Component { class PathSelector extends Component { Option = observer(PathSelectorOption); render() { + let regex: RegExp | null = null; + if (this.props.regexMode) { + try { + regex = new RegExp(this.props.searchQuery, "i"); + } catch { + toast.error("Invalid regular expression: " + this.props.searchQuery); + } + } const activePath = doc.pathlist.activePathUUID; const filteredPathEntries = Array.from(doc.pathlist.paths.entries()) - .filter(([, path]) => - path.name.toLowerCase().includes(this.props.searchQuery.toLowerCase().trim()) - ); - // .sort((a, b) => a[1].name.localeCompare(b[1].name)); + .filter(([, path]) => { + const query = this.props.searchQuery.trim(); + if (!query) return true; + return regex == null + ? path.name + .toLowerCase() + .includes(query.toLowerCase()) + : regex.test(path.name); + }); + if (this.props.sortAlphabetical) { + filteredPathEntries.sort((a, b) => a[1].name.localeCompare(b[1].name)); + } return (
diff --git a/src/components/sidebar/Sidebar.tsx b/src/components/sidebar/Sidebar.tsx index dfc8d3c237..b82baf25e5 100644 --- a/src/components/sidebar/Sidebar.tsx +++ b/src/components/sidebar/Sidebar.tsx @@ -13,7 +13,8 @@ import { Polyline, Undo, Search, - Clear + Clear, + Abc } from "@mui/icons-material"; import Add from "@mui/icons-material/Add"; import SidebarConstraint from "./SidebarConstraint"; @@ -56,18 +57,49 @@ class TrajectorySearch extends Component { sx={{ color: "gray", marginRight: "4px", - fontSize: "20px" + fontSize: "20px", }} /> ), - endAdornment: trajSearchQuery && ( - setTrajSearchQuery("")} - sx={{ padding: 0 }} - > - - + endAdornment: ( +
+ + + Re + + + {trajSearchQuery && ( + setTrajSearchQuery("")} + > + + + )} +
), style: { color: "white", @@ -122,7 +154,6 @@ class Sidebar extends Component { } render() { - const { toggleMainMenu, trajSearchQuery } = uiState; return (
@@ -141,7 +172,7 @@ class Sidebar extends Component { > - + @@ -180,9 +211,26 @@ class Sidebar extends Component {
PATHS + + + + + + + { className={styles.Sidebar} style={{ maxHeight: "300px", minHeight: "50px" }} > - +
FEATURES
diff --git a/src/document/UIStateStore.tsx b/src/document/UIStateStore.tsx index f32621ed61..8abc67794d 100644 --- a/src/document/UIStateStore.tsx +++ b/src/document/UIStateStore.tsx @@ -70,6 +70,8 @@ export const UIStateStore = types contextMenuMouseSelection: types.maybe(types.array(types.number)), // [clientX, clientY] from `MouseEvent` trajSearchQuery: types.maybe(types.string), + trajSearchRegex: false, + sortAlphabetical: false, }) .views((self: any) => { return { @@ -216,5 +218,11 @@ export const UIStateStore = types setTrajSearchQuery(query: string) { self.trajSearchQuery = query; }, + toggleTrajSearchRegex() { + self.trajSearchRegex = !self.trajSearchRegex; + }, + toggleSortAlphabetical() { + self.sortAlphabetical = !self.sortAlphabetical; + }, })); export type IUIStateStore = Instance; From ca41a0acd12d2122046551bb74a4862c10093207 Mon Sep 17 00:00:00 2001 From: Daniel1464 Date: Sun, 7 Jun 2026 10:24:14 -0400 Subject: [PATCH 3/3] fixed issue with search bar & lint --- src/components/sidebar/PathSelector.tsx | 11 +++++------ src/components/sidebar/Sidebar.tsx | 16 ++++++++++------ src/document/UIStateStore.tsx | 4 ++-- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/components/sidebar/PathSelector.tsx b/src/components/sidebar/PathSelector.tsx index 76171a9dbf..8bba4e377f 100644 --- a/src/components/sidebar/PathSelector.tsx +++ b/src/components/sidebar/PathSelector.tsx @@ -325,16 +325,15 @@ class PathSelector extends Component { } } const activePath = doc.pathlist.activePathUUID; - const filteredPathEntries = Array.from(doc.pathlist.paths.entries()) - .filter(([, path]) => { + const filteredPathEntries = Array.from(doc.pathlist.paths.entries()).filter( + ([, path]) => { const query = this.props.searchQuery.trim(); if (!query) return true; return regex == null - ? path.name - .toLowerCase() - .includes(query.toLowerCase()) + ? path.name.toLowerCase().includes(query.toLowerCase()) : regex.test(path.name); - }); + } + ); if (this.props.sortAlphabetical) { filteredPathEntries.sort((a, b) => a[1].name.localeCompare(b[1].name)); } diff --git a/src/components/sidebar/Sidebar.tsx b/src/components/sidebar/Sidebar.tsx index b82baf25e5..85a3e40e14 100644 --- a/src/components/sidebar/Sidebar.tsx +++ b/src/components/sidebar/Sidebar.tsx @@ -26,7 +26,6 @@ import ProjectSaveStatusIndicator from "./ProjectSaveStatusIndicator"; type Props = object; type State = object; - class TrajectorySearch extends Component { render() { const { trajSearchQuery, setTrajSearchQuery } = uiState; @@ -57,12 +56,12 @@ class TrajectorySearch extends Component { sx={{ color: "gray", marginRight: "4px", - fontSize: "20px", + fontSize: "20px" }} /> ), endAdornment: ( -
+ <> { )} -
+ ), style: { color: "white", @@ -141,7 +140,10 @@ class Sidebar extends Component { resize = (e: MouseEvent) => { const newWidth = Math.max(260, Math.min(560, e.clientX)); - document.documentElement.style.setProperty("--sidebar-width", `${newWidth}px`); + document.documentElement.style.setProperty( + "--sidebar-width", + `${newWidth}px` + ); }; stopResize = () => { @@ -223,7 +225,9 @@ class Sidebar extends Component { color="default" style={{ float: "right" }} sx={{ - color: uiState.sortAlphabetical ? "var(--accent-purple)" : "white" + color: uiState.sortAlphabetical + ? "var(--accent-purple)" + : "white" }} onClick={uiState.toggleSortAlphabetical} > diff --git a/src/document/UIStateStore.tsx b/src/document/UIStateStore.tsx index 8abc67794d..c47a34b4b2 100644 --- a/src/document/UIStateStore.tsx +++ b/src/document/UIStateStore.tsx @@ -71,7 +71,7 @@ export const UIStateStore = types trajSearchQuery: types.maybe(types.string), trajSearchRegex: false, - sortAlphabetical: false, + sortAlphabetical: false }) .views((self: any) => { return { @@ -223,6 +223,6 @@ export const UIStateStore = types }, toggleSortAlphabetical() { self.sortAlphabetical = !self.sortAlphabetical; - }, + } })); export type IUIStateStore = Instance;