refactor: open search from titlebar command
This commit is contained in:
@@ -73,14 +73,12 @@ export default function GlobalSearch({ settings }: GlobalSearchProps) {
|
||||
const [filtersOpen, setFiltersOpen] = useState(false);
|
||||
const [activeIndex, setActiveIndex] = useState(-1);
|
||||
|
||||
const rootRef = useRef<HTMLDivElement>(null);
|
||||
const sourceInputRef = useRef<HTMLInputElement>(null);
|
||||
const rootRef = useRef<HTMLButtonElement>(null);
|
||||
const overlayInputRef = useRef<HTMLInputElement>(null);
|
||||
const filtersRef = useRef<HTMLDivElement>(null);
|
||||
const resultsRef = useRef<HTMLDivElement>(null);
|
||||
const requestSequenceRef = useRef(0);
|
||||
const loadMoreControllerRef = useRef<AbortController | null>(null);
|
||||
const suppressRestoredFocusRef = useRef(false);
|
||||
|
||||
const effectiveModules = useMemo(
|
||||
() => scope === "context" && currentContext
|
||||
@@ -152,7 +150,6 @@ export default function GlobalSearch({ settings }: GlobalSearchProps) {
|
||||
|
||||
const closeOverlay = useCallback(() => {
|
||||
loadMoreControllerRef.current?.abort();
|
||||
suppressRestoredFocusRef.current = true;
|
||||
setOpen(false);
|
||||
setFiltersOpen(false);
|
||||
setActiveIndex(-1);
|
||||
@@ -163,14 +160,6 @@ export default function GlobalSearch({ settings }: GlobalSearchProps) {
|
||||
setOpen(true);
|
||||
}, [measureOverlay]);
|
||||
|
||||
const handleSourceFocus = useCallback(() => {
|
||||
if (suppressRestoredFocusRef.current) {
|
||||
suppressRestoredFocusRef.current = false;
|
||||
return;
|
||||
}
|
||||
openOverlay();
|
||||
}, [openOverlay]);
|
||||
|
||||
useEffect(() => {
|
||||
function focusSearch(event: KeyboardEvent) {
|
||||
const commandSearch =
|
||||
@@ -395,41 +384,26 @@ export default function GlobalSearch({ settings }: GlobalSearchProps) {
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
<button
|
||||
ref={rootRef}
|
||||
className={`global-search global-search-source${open ? " is-overlay-open" : ""}`}>
|
||||
<Search size={16} aria-hidden="true" />
|
||||
<input
|
||||
ref={sourceInputRef}
|
||||
type="search"
|
||||
value={query}
|
||||
readOnly
|
||||
tabIndex={open ? -1 : 0}
|
||||
placeholder={currentContext?.placeholder ?? "Search"}
|
||||
aria-label="Global search"
|
||||
aria-keyshortcuts="F3 Control+K Meta+K"
|
||||
aria-expanded={open}
|
||||
onFocus={handleSourceFocus}
|
||||
onClick={openOverlay}
|
||||
/>
|
||||
{query &&
|
||||
<button
|
||||
type="button"
|
||||
className="global-search-clear"
|
||||
tabIndex={open ? -1 : 0}
|
||||
aria-label="Clear search"
|
||||
onClick={() => {
|
||||
setQuery("");
|
||||
setResponse(null);
|
||||
}}>
|
||||
<X size={14} />
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
type="button"
|
||||
data-help-context-id="search.global"
|
||||
data-help-module-id="search"
|
||||
data-help-scope="action"
|
||||
className={`titlebar-icon-link titlebar-search-button${open ? " is-context-active" : ""}`}
|
||||
title="Search (F3 / Ctrl+K)"
|
||||
aria-label="Global search"
|
||||
aria-keyshortcuts="F3 Control+K Meta+K"
|
||||
aria-haspopup="dialog"
|
||||
aria-expanded={open}
|
||||
onClick={openOverlay}>
|
||||
<Search size={18} aria-hidden="true" />
|
||||
</button>
|
||||
|
||||
<Dialog
|
||||
open={open && Boolean(layout)}
|
||||
title="Search"
|
||||
helpContextId="search.results"
|
||||
onClose={closeOverlay}
|
||||
showCloseButton={false}
|
||||
portal
|
||||
|
||||
@@ -33,16 +33,9 @@ export function calculateSearchOverlayLayout(
|
||||
const mobile = viewportWidth < MOBILE_BREAKPOINT;
|
||||
const margin = mobile ? MOBILE_MARGIN : DESKTOP_MARGIN;
|
||||
const width = Math.max(1, Math.min(DESKTOP_PANEL_WIDTH, viewportWidth - margin * 2));
|
||||
const centeredLeft = anchor.left + anchor.width / 2 - width / 2;
|
||||
const left = mobile
|
||||
? margin
|
||||
: clamp(centeredLeft, margin, Math.max(margin, viewportWidth - width - margin));
|
||||
const inputWidth = mobile
|
||||
? width
|
||||
: Math.min(Math.max(1, anchor.width), width);
|
||||
const inputOffset = mobile
|
||||
? 0
|
||||
: clamp(anchor.left - left, 0, Math.max(0, width - inputWidth));
|
||||
const left = Math.max(margin, (viewportWidth - width) / 2);
|
||||
const inputWidth = width;
|
||||
const inputOffset = 0;
|
||||
const top = Math.max(0, anchor.top);
|
||||
const inputHeight = Math.max(1, anchor.height);
|
||||
const availableResultsHeight = viewportHeight - top - inputHeight - RESULTS_GAP - margin;
|
||||
@@ -89,7 +82,3 @@ function normalizePath(value: string): string {
|
||||
const normalized = `/${String(value || "").trim().replace(/^\/+|\/+$/g, "")}`;
|
||||
return normalized === "/" ? normalized : normalized.replace(/\/+$/g, "");
|
||||
}
|
||||
|
||||
function clamp(value: number, minimum: number, maximum: number): number {
|
||||
return Math.min(Math.max(value, minimum), maximum);
|
||||
}
|
||||
|
||||
@@ -53,10 +53,6 @@
|
||||
color: var(--text-strong);
|
||||
}
|
||||
|
||||
.global-search-source.is-overlay-open {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.search-overlay-backdrop {
|
||||
display: block;
|
||||
padding: 0;
|
||||
@@ -110,7 +106,7 @@
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
flex-direction: column;
|
||||
margin-top: -44px;
|
||||
margin-top: 8px;
|
||||
overflow: hidden;
|
||||
border: var(--border-line);
|
||||
border-radius: 6px;
|
||||
@@ -464,19 +460,6 @@
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.global-search-source {
|
||||
width: 34px;
|
||||
min-width: 34px;
|
||||
padding: 0 8px;
|
||||
}
|
||||
|
||||
.global-search-source input,
|
||||
.global-search-source .global-search-clear {
|
||||
width: 0;
|
||||
padding: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.search-overlay-results-panel {
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user