mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-11-28 05:37:34 +03:00
Added search highlight on title and excerpt
refs https://github.com/TryGhost/Team/issues/1665 - adds bold highlight for search term for title and excerpt - needs logic to truncate to show excerpt highlight if it cuts out
This commit is contained in:
parent
70cbf57f35
commit
e4213a223d
@ -45,8 +45,8 @@ const authorsData = [
|
||||
}
|
||||
];
|
||||
|
||||
const DEFAULT_MAX_POSTS = 1;
|
||||
const STEP_MAX_POSTS = 1;
|
||||
const DEFAULT_MAX_POSTS = 10;
|
||||
const STEP_MAX_POSTS = 10;
|
||||
|
||||
const StylesWrapper = () => {
|
||||
return {
|
||||
@ -230,6 +230,7 @@ function TagResults({tags, selectedResult, setSelectedResult}) {
|
||||
}
|
||||
|
||||
function PostListItem({post, selectedResult, setSelectedResult}) {
|
||||
const {searchValue} = useContext(AppContext);
|
||||
const {title, excerpt, url, id} = post;
|
||||
let className = 'py-3 -mx-4 sm:-mx-7 px-4 sm:px-7 cursor-pointer';
|
||||
if (id === selectedResult) {
|
||||
@ -247,12 +248,88 @@ function PostListItem({post, selectedResult, setSelectedResult}) {
|
||||
setSelectedResult(id);
|
||||
}}
|
||||
>
|
||||
<h2 className='text-[1.65rem] font-medium leading-tight text-neutral-900'><span dangerouslySetInnerHTML={{__html: title}} /></h2>
|
||||
<p className='text-neutral-400 leading-normal text-sm mt-0 mb-0 truncate'><span dangerouslySetInnerHTML={{__html: excerpt}} /></p>
|
||||
<h2 className='text-[1.65rem] font-medium leading-tight text-neutral-900'>
|
||||
<HighlightedSection text={title} highlight={searchValue} />
|
||||
</h2>
|
||||
<p className='text-neutral-400 leading-normal text-sm mt-0 mb-0 truncate'>
|
||||
<HighlightedSection text={excerpt} highlight={searchValue} />
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function HighlightedSection({text, highlight}) {
|
||||
const highlightStartIndex = text.toLowerCase().indexOf(highlight.toLowerCase());
|
||||
let parts = [];
|
||||
if (highlightStartIndex === 0) {
|
||||
parts.push({
|
||||
text: text?.slice(0, highlight?.length),
|
||||
type: 'highlight'
|
||||
});
|
||||
let nextSection = text?.slice(highlight?.length, text?.length);
|
||||
if (nextSection) {
|
||||
parts.push({
|
||||
text: nextSection,
|
||||
type: 'normal'
|
||||
});
|
||||
}
|
||||
} else if (highlightStartIndex > 0) {
|
||||
parts.push({
|
||||
text: text?.slice(0, highlightStartIndex),
|
||||
type: 'normal'
|
||||
});
|
||||
let highlightSection = text?.slice(highlightStartIndex, highlightStartIndex + highlight?.length);
|
||||
if (highlightSection) {
|
||||
parts.push({
|
||||
text: highlightSection,
|
||||
type: 'highlight'
|
||||
});
|
||||
}
|
||||
if (highlightStartIndex + highlight?.length < text.length) {
|
||||
let nextSection = text?.slice(highlightStartIndex + highlight?.length);
|
||||
parts.push({
|
||||
text: nextSection,
|
||||
type: 'normal'
|
||||
});
|
||||
}
|
||||
} else {
|
||||
parts.push({
|
||||
text: text,
|
||||
type: 'normal'
|
||||
});
|
||||
}
|
||||
const wordMap = parts.map((d, idx) => {
|
||||
if (d?.type === 'highlight') {
|
||||
return (
|
||||
<React.Fragment key={idx}>
|
||||
<HighlightWord word={d.text} highlight={highlight} />
|
||||
</React.Fragment>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<React.Fragment key={idx}>
|
||||
{d.text}
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
});
|
||||
return (
|
||||
<>
|
||||
{wordMap}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function HighlightWord({word, highlight}) {
|
||||
const firstHalf = word.slice(0, (highlight?.length || 0)) || '';
|
||||
const secondHalf = word.slice((highlight?.length || 0), (word?.length || 1000)) || '';
|
||||
return (
|
||||
<>
|
||||
<span className='font-bold'>{firstHalf}</span>{secondHalf}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function ShowMoreButton({posts, maxPosts, setMaxPosts}) {
|
||||
if (!posts?.length || maxPosts >= posts?.length) {
|
||||
return null;
|
||||
|
Loading…
Reference in New Issue
Block a user