From a547af1de3160db0a6147a7079d22ef00fc54a3c Mon Sep 17 00:00:00 2001 From: yu-i-i Date: Tue, 14 Jul 2026 03:05:48 +0200 Subject: [PATCH] Reference picker: improve usability - show tags for nonexistent references - click a badge to find the corresponding reference --- .../components/reference-picker-modal.tsx | 46 +++++++++++++++---- .../frontend/styles/reference-picker.scss | 22 +++++++-- 2 files changed, 55 insertions(+), 13 deletions(-) diff --git a/services/web/modules/reference-picker/frontend/components/reference-picker-modal.tsx b/services/web/modules/reference-picker/frontend/components/reference-picker-modal.tsx index 700b888380..f818863adf 100644 --- a/services/web/modules/reference-picker/frontend/components/reference-picker-modal.tsx +++ b/services/web/modules/reference-picker/frontend/components/reference-picker-modal.tsx @@ -74,6 +74,7 @@ export default function ReferencePickerModal({ const [query, setQuery] = useState('') const [selectedKeys, setSelectedKeys] = useState([]) const [results, setResults] = useState<{ _source: Bib2JsonEntry }[]>([]) + const [knownKeys, setKnownKeys] = useState>(() => new Set()) const pendingInitialKeysRef = useRef([]) const requestIdRef = useRef(0) @@ -109,9 +110,9 @@ export default function ReferencePickerModal({ setResults(r.hits) if (pendingInitialKeysRef.current.length > 0) { - const knownKeys = new Set(r.hits.map(h => h._source.EntryKey)) - const matched = pendingInitialKeysRef.current.filter(k => knownKeys.has(k)) - if (matched.length > 0) setSelectedKeys(matched) + const known = new Set(r.hits.map(h => h._source.EntryKey)) + setKnownKeys(known) + setSelectedKeys([...pendingInitialKeysRef.current]) pendingInitialKeysRef.current = [] } } @@ -143,6 +144,26 @@ export default function ReferencePickerModal({ const cancelButtonRef = useRef(null) const insertButtonRef = useRef(null) +const scrollToReference = useCallback((key: string) => { + const index = results.findIndex( + r => r._source.EntryKey === key + ) + + if (index === -1) return + + const el = document.getElementById( + `reference-picker-item-${index}` + ) + + el?.scrollIntoView({ + behavior: 'smooth', + block: 'nearest', + }) + + setFocusArea('list') + setFocusedIndex(index) +}, [results]) + const removeOne = useCallback((key: string) => { setSelectedKeys(prev => { const index = prev.indexOf(key) @@ -300,14 +321,23 @@ export default function ReferencePickerModal({ -
+
{selectedKeys.map((key, idx) => ( - removeOne(key) }} + className={ + knownKeys.has(key) + ? 'existing-key-tag' + : 'nonexistent-key-tag' + } > - {key} - + scrollToReference(key) }} + closeBtnProps={{ onClick: () => removeOne(key) }} + > + {key} + + ))}
diff --git a/services/web/modules/reference-picker/frontend/styles/reference-picker.scss b/services/web/modules/reference-picker/frontend/styles/reference-picker.scss index 3b1aaf659a..3589d5bc10 100644 --- a/services/web/modules/reference-picker/frontend/styles/reference-picker.scss +++ b/services/web/modules/reference-picker/frontend/styles/reference-picker.scss @@ -1,5 +1,5 @@ .references-search-modal { - .selected-key-tag { + .selected-key-tags { position: relative; display: flex; flex-wrap: wrap; @@ -13,10 +13,22 @@ margin-bottom: 8px; box-shadow: 0 1px 0 var(--ds-color-neutral-100); padding-bottom: 6px; - - .badge-tag { - background-color:var(--ds-color-green-50) !important; - } + } + .selected-key-tags .existing-key-tag .badge-tag { + background-color: var(--ds-color-green-50) !important; + } + .selected-key-tags .nonexistent-key-tag .badge-tag { + background-color: var(--ds-color-red-50) !important; + } + .existing-key-tag .badge-tag-content-btn:hover { + background-color: var(--ds-color-green-100); + } + .nonexistent-key-tag .badge-tag-content-btn:hover { + background-color: transparent; + } + .badge-close:hover, + .badge-close:focus { + background-color: var(--ds-color-neutral-100); } .search-results {