Skip to content

Commit b64cda6

Browse files
authored
feat: highlight the text when search database or table (#97)
* add dummy search highlight * feat: add highlight when search * fix code smell
1 parent bf8ce3e commit b64cda6

File tree

5 files changed

+53
-3
lines changed

5 files changed

+53
-3
lines changed

src/renderer/components/DatabaseTable/DatabaseSelection.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ function DatabaseSelectionModal({
3737
const { common } = useSqlExecute();
3838

3939
const filteredDatabaseList = useMemo(() => {
40-
return databaseList.filter(database =>
40+
return databaseList.filter((database) =>
4141
database.toLowerCase().includes(searchTerm.toLowerCase())
4242
);
4343
}, [databaseList, searchTerm]);
@@ -82,6 +82,7 @@ function DatabaseSelectionModal({
8282
<p className={styles.noResultsText}>No matching databases found.</p>
8383
) : (
8484
<ListView
85+
highlight={searchTerm || undefined}
8586
selectedItem={selectedDatabase}
8687
onSelectChange={(item) => setSelectedDatabase(item)}
8788
items={filteredDatabaseList}

src/renderer/components/DatabaseTable/DatabaseTableList.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,8 @@ export default function DatabaseTableList() {
179179
<Layout.Grow>
180180
{currentDatabase ? (
181181
<TreeView
182+
highlight={search || undefined}
183+
highlightDepth={1}
182184
selected={selected}
183185
onSelectChange={setSelected}
184186
collapsedKeys={collapsed}

src/renderer/components/ListView/index.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import ListViewItem from '../ListViewItem';
33

44
interface ListViewProps<T> {
55
items: T[];
6+
highlight?: string;
67
selectedItem?: T;
78
changeItemKeys?: string[];
89
emptyComponent?: ReactElement;
@@ -20,6 +21,7 @@ interface ListViewProps<T> {
2021

2122
export default function ListView<T>({
2223
items,
24+
highlight,
2325
selectedItem,
2426
changeItemKeys,
2527
extractMeta,
@@ -64,6 +66,7 @@ export default function ListView<T>({
6466
key={key}
6567
text={text}
6668
icon={icon}
69+
highlight={highlight}
6770
selected={key === selectedKey}
6871
changed={changeItemKeys?.includes(key)}
6972
onContextMenu={async (e) => {

src/renderer/components/ListViewItem/index.tsx

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
import { ReactElement } from 'react';
1+
import { ReactElement, useMemo } from 'react';
22
import styles from './styles.module.scss';
33
import Icon from '../Icon';
44
import { useAppFeature } from 'renderer/contexts/AppFeatureProvider';
55

66
interface ListViewItemProps {
77
text: string;
8+
highlight?: string;
89
icon?: ReactElement;
910
changed?: boolean;
1011
selected?: boolean;
@@ -19,8 +20,16 @@ interface ListViewItemProps {
1920
onCollapsedClick?: () => void;
2021
}
2122

23+
function encodeStringToHTML(s: string) {
24+
const el = document.createElement('div');
25+
el.innerText = el.textContent = s;
26+
s = el.innerHTML;
27+
return s;
28+
}
29+
2230
export default function ListViewItem({
2331
text,
32+
highlight,
2433
icon,
2534
selected,
2635
changed,
@@ -36,6 +45,24 @@ export default function ListViewItem({
3645
}: ListViewItemProps) {
3746
const { theme } = useAppFeature();
3847

48+
const finalText = useMemo(() => {
49+
if (highlight) {
50+
const highlightText = encodeStringToHTML(highlight);
51+
const santizedText = encodeStringToHTML(text || '');
52+
const regex = new RegExp(
53+
'(' + highlightText.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + ')',
54+
'i'
55+
);
56+
57+
return santizedText.replace(
58+
regex,
59+
`<mark style="padding: 0; background-color: #047bf8; color: white">$1</mark>`
60+
);
61+
} else {
62+
return encodeStringToHTML(text || '');
63+
}
64+
}, [text, highlight]);
65+
3966
return (
4067
<div
4168
className={[
@@ -76,7 +103,10 @@ export default function ListViewItem({
76103
</div>
77104
))}
78105
{!hasCollapsed && <div className={styles.icon}>{icon}</div>}
79-
<div className={styles.text}>{text}</div>
106+
<div
107+
className={styles.text}
108+
dangerouslySetInnerHTML={{ __html: finalText }}
109+
/>
80110
</div>
81111
);
82112
}

src/renderer/components/TreeView/index.tsx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ interface TreeViewProps<T> {
1818
onSelectChange?: (value?: TreeViewItemData<T>) => void;
1919
onDoubleClick?: (value: TreeViewItemData<T>) => void;
2020
onContextMenu?: React.MouseEventHandler;
21+
highlight?: string;
22+
highlightDepth?: number;
2123
}
2224

2325
function TreeViewItem<T>({
@@ -30,6 +32,9 @@ function TreeViewItem<T>({
3032
collapsedKeys,
3133
onCollapsedChange,
3234
onDoubleClick,
35+
36+
highlight,
37+
highlightDepth,
3338
}: {
3439
item: TreeViewItemData<T>;
3540
depth: number;
@@ -40,6 +45,8 @@ function TreeViewItem<T>({
4045
onCollapsedChange?: (value?: string[]) => void;
4146
collapsedKeys?: string[];
4247
onDoubleClick?: (value: TreeViewItemData<T>) => void;
48+
highlight?: string;
49+
highlightDepth?: number;
4350
}) {
4451
const hasCollapsed = item.children && item.children.length > 0;
4552
const isCollapsed = collapsedKeys?.includes(item.id);
@@ -62,6 +69,7 @@ function TreeViewItem<T>({
6269
onDoubleClick(item);
6370
}
6471
}}
72+
highlight={depth === highlightDepth ? highlight : undefined}
6573
hasCollapsed={hasCollapsed}
6674
collapsed={isCollapsed}
6775
selected={selected?.id === item.id}
@@ -89,6 +97,8 @@ function TreeViewItem<T>({
8997
key={item.id}
9098
item={item}
9199
depth={depth + 1}
100+
highlight={highlight}
101+
highlightDepth={highlightDepth}
92102
selected={selected}
93103
onSelectChange={onSelectChange}
94104
collapsedKeys={collapsedKeys}
@@ -111,6 +121,8 @@ export default function TreeView<T>({
111121
collapsedKeys,
112122
onDoubleClick,
113123
onContextMenu,
124+
highlight,
125+
highlightDepth,
114126
}: TreeViewProps<T>) {
115127
return (
116128
<div className={`${styles.treeView} scroll`} onContextMenu={onContextMenu}>
@@ -120,6 +132,8 @@ export default function TreeView<T>({
120132
key={item.id}
121133
item={item}
122134
depth={0}
135+
highlight={highlight}
136+
highlightDepth={highlightDepth}
123137
selected={selected}
124138
onSelectChange={onSelectChange}
125139
onDoubleClick={onDoubleClick}

0 commit comments

Comments
 (0)