Skip to content

Commit d3904c0

Browse files
committed
more fix. but need to figure out tailwindcss bug
1 parent b82b99d commit d3904c0

1 file changed

Lines changed: 226 additions & 85 deletions

File tree

  • apps/roam/src/components/AdvancedNodeSearchDialog

apps/roam/src/components/AdvancedNodeSearchDialog/index.tsx

Lines changed: 226 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,141 @@ import {
3838

3939
type Props = Record<string, unknown>;
4040

41+
const dialogStyle: React.CSSProperties = {
42+
display: "flex",
43+
flexDirection: "column",
44+
height: "72vh",
45+
maxWidth: "980px",
46+
overflow: "hidden",
47+
padding: 0,
48+
width: "min(980px, calc(100vw - 64px))",
49+
};
50+
51+
const modalStyle: React.CSSProperties = {
52+
display: "flex",
53+
flex: 1,
54+
flexDirection: "column",
55+
margin: 0,
56+
minHeight: 0,
57+
overflow: "hidden",
58+
padding: 0,
59+
pointerEvents: "all",
60+
};
61+
62+
const searchHeaderStyle: React.CSSProperties = {
63+
alignItems: "center",
64+
borderBottom: "1px solid rgba(31, 31, 31, 0.12)",
65+
display: "flex",
66+
flexShrink: 0,
67+
gap: "8px",
68+
padding: "12px 16px",
69+
};
70+
71+
const bodyStyle: React.CSSProperties = {
72+
display: "flex",
73+
flex: 1,
74+
minHeight: 0,
75+
overflow: "hidden",
76+
};
77+
78+
const resultsPanelStyle: React.CSSProperties = {
79+
borderRight: "1px solid rgba(31, 31, 31, 0.12)",
80+
flexShrink: 0,
81+
minHeight: 0,
82+
overflowY: "auto",
83+
width: "38%",
84+
};
85+
86+
const previewColumnStyle: React.CSSProperties = {
87+
display: "flex",
88+
flex: 1,
89+
flexDirection: "column",
90+
minHeight: 0,
91+
overflow: "hidden",
92+
};
93+
94+
const previewPanelStyle: React.CSSProperties = {
95+
flex: 1,
96+
minHeight: 0,
97+
overflowY: "auto",
98+
padding: "32px",
99+
};
100+
101+
const emptyPanelStyle: React.CSSProperties = {
102+
alignItems: "center",
103+
display: "flex",
104+
height: "100%",
105+
justifyContent: "center",
106+
padding: "24px",
107+
};
108+
109+
const messagePanelStyle: React.CSSProperties = {
110+
alignItems: "center",
111+
color: "rgba(31, 31, 31, 0.5)",
112+
display: "flex",
113+
flex: 1,
114+
fontSize: "14px",
115+
justifyContent: "center",
116+
minHeight: 0,
117+
padding: "48px 16px",
118+
textAlign: "center",
119+
width: "100%",
120+
};
121+
122+
const focusSearchInput = (input: HTMLInputElement | null): void => {
123+
input?.focus();
124+
};
125+
126+
const resultTitleStyle: React.CSSProperties = {
127+
color: "#1f1f1f",
128+
fontSize: "14px",
129+
lineHeight: 1.4,
130+
wordBreak: "break-word",
131+
};
132+
133+
const resultExcerptStyle: React.CSSProperties = {
134+
color: "rgba(31, 31, 31, 0.55)",
135+
display: "block",
136+
fontSize: "12px",
137+
lineHeight: 1.35,
138+
marginTop: "4px",
139+
};
140+
141+
const previewTitleStyle: React.CSSProperties = {
142+
color: "#1f1f1f",
143+
fontSize: "22px",
144+
lineHeight: 1.25,
145+
margin: "14px 0",
146+
};
147+
148+
const previewMetaStyle: React.CSSProperties = {
149+
color: "rgba(31, 31, 31, 0.55)",
150+
fontSize: "12px",
151+
letterSpacing: "0.02em",
152+
};
153+
154+
const previewBodyStyle: React.CSSProperties = {
155+
borderTop: "1px solid rgba(31, 31, 31, 0.12)",
156+
color: "#1f1f1f",
157+
fontSize: "15px",
158+
lineHeight: 1.55,
159+
marginTop: "24px",
160+
paddingTop: "16px",
161+
};
162+
163+
const getResultRowStyle = (active: boolean): React.CSSProperties => ({
164+
alignItems: "flex-start",
165+
background: active ? "rgba(95, 87, 192, 0.08)" : "transparent",
166+
border: 0,
167+
boxShadow: active ? "inset 3px 0 0 #5f57c0" : undefined,
168+
cursor: "pointer",
169+
display: "flex",
170+
gap: "10px",
171+
padding: "12px 16px",
172+
textAlign: "left",
173+
width: "100%",
174+
});
175+
41176
const getNodeBadgeText = (node: DiscourseNode): string =>
42177
(node.tag?.trim() || node.text).slice(0, 3).toUpperCase();
43178

@@ -79,24 +214,21 @@ const ResultRow = ({
79214
<button
80215
type="button"
81216
aria-selected={active}
82-
className={`flex w-full cursor-pointer gap-2.5 border-0 px-4 py-3 text-left ${
83-
active ? "bg-blue-50" : "bg-transparent"
84-
}`}
217+
className="dg-advanced-node-search-result"
85218
onClick={onClick}
86219
onMouseEnter={onMouseEnter}
87220
role="option"
221+
style={getResultRowStyle(active)}
88222
>
89223
<Tag minimal style={getTagStyle(nodeConfig)}>
90224
{nodeConfig ? getNodeBadgeText(nodeConfig) : result.nodeTypeLabel}
91225
</Tag>
92-
<span className="min-w-0">
93-
<span className="text-sm leading-snug text-gray-900">
226+
<span style={{ minWidth: 0 }}>
227+
<span style={resultTitleStyle}>
94228
{renderHighlightedText(stripTypePrefix(result.title), keywords)}
95229
</span>
96230
{result.excerpt && (
97-
<span className="mt-1 block text-xs leading-snug text-gray-500">
98-
{result.excerpt}
99-
</span>
231+
<span style={resultExcerptStyle}>{result.excerpt}</span>
100232
)}
101233
</span>
102234
</button>
@@ -117,37 +249,41 @@ const PreviewPane = ({
117249
}) => {
118250
if (!result) {
119251
return (
120-
<div className="flex h-full items-center justify-center p-6">
121-
<NonIdealState
122-
icon="search"
123-
title="Search DG nodes"
124-
description="Type a keyword to preview matching discourse graph nodes."
125-
/>
252+
<div style={previewColumnStyle}>
253+
<div style={emptyPanelStyle}>
254+
<NonIdealState
255+
icon="search"
256+
title="Search DG nodes"
257+
description="Type a keyword to preview matching discourse graph nodes."
258+
/>
259+
</div>
126260
</div>
127261
);
128262
}
129263

130264
if (isLoading || !content) {
131265
return (
132-
<div className="flex h-full items-center justify-center p-6">
133-
<Spinner size={SpinnerSize.SMALL} />
266+
<div style={previewColumnStyle}>
267+
<div style={emptyPanelStyle}>
268+
<Spinner size={SpinnerSize.SMALL} />
269+
</div>
134270
</div>
135271
);
136272
}
137273

138274
return (
139-
<div className="overflow-y-auto p-8">
275+
<div style={previewPanelStyle}>
140276
<Tag minimal style={getTagStyle(nodeConfig)}>
141277
{nodeConfig ? nodeConfig.text : result.nodeTypeLabel}
142278
</Tag>
143-
<h2 className="my-3.5 text-2xl leading-tight text-gray-900">
279+
<h2 style={previewTitleStyle}>
144280
{renderHighlightedText(stripTypePrefix(content.title), keywords)}
145281
</h2>
146-
<div className="text-xs tracking-wide text-gray-500">
282+
<div style={previewMetaStyle}>
147283
Last modified: {formatMetadataDate(result.lastModified)} · Created:{" "}
148284
{formatMetadataDate(result.createdAt)} · Author: {result.authorName}
149285
</div>
150-
<div className="mt-6 border-t border-gray-200 pt-4 text-[15px] leading-relaxed text-gray-900">
286+
<div style={previewBodyStyle}>
151287
{content.lines.length ? (
152288
content.lines.map((line, index) => <p key={index}>{line}</p>)
153289
) : (
@@ -197,7 +333,17 @@ const AdvancedNodeSearchDialog = ({
197333

198334
useEffect(() => {
199335
if (!isOpen) return;
200-
inputRef.current?.focus();
336+
337+
const focusInput = () => focusSearchInput(inputRef.current);
338+
339+
focusInput();
340+
const rafId = requestAnimationFrame(focusInput);
341+
const timeoutId = window.setTimeout(focusInput, 0);
342+
343+
return () => {
344+
cancelAnimationFrame(rafId);
345+
window.clearTimeout(timeoutId);
346+
};
201347
}, [isOpen]);
202348

203349
useEffect(() => {
@@ -372,27 +518,33 @@ const AdvancedNodeSearchDialog = ({
372518
results.length,
373519
]);
374520

521+
const showSplitView = contentState === "results";
522+
375523
return (
376524
<Dialog
377525
autoFocus={false}
378526
canEscapeKeyClose
379527
canOutsideClickClose
380-
className="roamjs-canvas-dialog w-[min(980px,calc(100vw-64px))] max-w-[980px]"
528+
className="roamjs-canvas-dialog"
529+
enforceFocus={false}
381530
isOpen={isOpen}
382531
onClose={onClose}
383-
title="DG node search"
532+
style={dialogStyle}
384533
>
385534
<div
386-
className="pointer-events-auto"
387535
onClick={(event) => event.stopPropagation()}
388536
onKeyDown={onKeyDown}
389537
onMouseDown={(event) => event.stopPropagation()}
390538
onMouseUp={(event) => event.stopPropagation()}
539+
style={modalStyle}
391540
>
392-
<div className="flex items-center gap-2 border-b border-gray-200 px-4 py-3">
541+
<div style={searchHeaderStyle}>
393542
<InputGroup
394543
fill
395-
inputRef={inputRef}
544+
inputRef={(element) => {
545+
inputRef.current = element;
546+
if (isOpen) focusSearchInput(element);
547+
}}
396548
leftIcon="search"
397549
onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
398550
setSearchTerm(event.target.value)
@@ -402,67 +554,56 @@ const AdvancedNodeSearchDialog = ({
402554
/>
403555
<Button icon="cross" minimal onClick={onClose} title="Close search" />
404556
</div>
405-
<div className="grid h-[560px] min-h-[420px] grid-cols-[minmax(280px,38%)_minmax(0,1fr)]">
406-
<div
407-
aria-label="Search results"
408-
className="overflow-y-auto border-r border-gray-200"
409-
ref={resultsPanelRef}
410-
role="listbox"
411-
>
412-
{contentState === "error" && (
413-
<div className="flex h-full items-center justify-center p-6">
414-
<NonIdealState
415-
icon="error"
416-
title="Search unavailable"
417-
description="Reload the extension and try again."
418-
/>
557+
<div style={bodyStyle}>
558+
{showSplitView ? (
559+
<>
560+
<div
561+
aria-label="Search results"
562+
ref={resultsPanelRef}
563+
role="listbox"
564+
style={resultsPanelStyle}
565+
>
566+
{results.map((result, index) => (
567+
<ResultRow
568+
active={index === activeIndex}
569+
key={result.uid}
570+
keywords={keywords}
571+
nodeConfig={nodeConfigByType[result.type]}
572+
onClick={() => setActiveIndex(index)}
573+
onMouseEnter={() => setActiveIndex(index)}
574+
result={result}
575+
/>
576+
))}
419577
</div>
420-
)}
421-
{contentState === "indexing" && (
422-
<div className="flex h-full items-center justify-center p-6">
578+
<PreviewPane
579+
content={activeContent}
580+
isLoading={
581+
isEnrichingResults &&
582+
!!activeResult &&
583+
!contentCacheRef.current.has(activeResult.uid)
584+
}
585+
keywords={keywords}
586+
nodeConfig={
587+
activeResult ? nodeConfigByType[activeResult.type] : undefined
588+
}
589+
result={activeResult}
590+
/>
591+
</>
592+
) : (
593+
<div style={messagePanelStyle}>
594+
{contentState === "indexing" && (
423595
<Spinner size={SpinnerSize.SMALL} />
424-
</div>
425-
)}
426-
{contentState === "initial" && (
427-
<div className="flex h-full items-center justify-center p-6">
428-
<NonIdealState title="Search DG nodes" />
429-
</div>
430-
)}
431-
{contentState === "empty" && (
432-
<div className="flex h-full items-center justify-center p-6">
433-
<NonIdealState
434-
icon="search"
435-
title="No results"
436-
description="Try another keyword."
437-
/>
438-
</div>
439-
)}
440-
{contentState === "results" &&
441-
results.map((result, index) => (
442-
<ResultRow
443-
active={index === activeIndex}
444-
key={result.uid}
445-
keywords={keywords}
446-
nodeConfig={nodeConfigByType[result.type]}
447-
onClick={() => setActiveIndex(index)}
448-
onMouseEnter={() => setActiveIndex(index)}
449-
result={result}
450-
/>
451-
))}
452-
</div>
453-
<PreviewPane
454-
content={activeContent}
455-
isLoading={
456-
isEnrichingResults &&
457-
!!activeResult &&
458-
!contentCacheRef.current.has(activeResult.uid)
459-
}
460-
keywords={keywords}
461-
nodeConfig={
462-
activeResult ? nodeConfigByType[activeResult.type] : undefined
463-
}
464-
result={activeResult}
465-
/>
596+
)}
597+
{contentState === "empty" && (
598+
<span>No matches. Try another keyword.</span>
599+
)}
600+
{contentState === "error" && (
601+
<span>
602+
Search unavailable. Reload the extension and try again.
603+
</span>
604+
)}
605+
</div>
606+
)}
466607
</div>
467608
</div>
468609
</Dialog>

0 commit comments

Comments
 (0)