feat: allow merging of adjacent search results
This commit is contained in:
@@ -243,3 +243,48 @@ h2 {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.search-result-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.merge-button-wrapper {
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 2em;
|
||||||
|
position: relative;
|
||||||
|
align-self: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.merge-button {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, 50%);
|
||||||
|
z-index: 10;
|
||||||
|
background-color: #888;
|
||||||
|
border: 1px solid #aaa;
|
||||||
|
border-radius: 50%;
|
||||||
|
color: white;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
line-height: 1;
|
||||||
|
height: 1.5em;
|
||||||
|
width: 1.5em;
|
||||||
|
padding: 0;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.merge-button:hover {
|
||||||
|
background-color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-result-button-wrapper {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-result-button-wrapper button {
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|||||||
@@ -515,7 +515,8 @@ function Menu({data, duration, setDuration, end, setEnd, slider, setSlider, subm
|
|||||||
);
|
);
|
||||||
|
|
||||||
setActiveSearchResult(null);
|
setActiveSearchResult(null);
|
||||||
setSearchResults(res.data);
|
const sortedData = res.data.sort((a, b) => b.start - a.start);
|
||||||
|
setSearchResults(sortedData);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error during area search:', error);
|
console.error('Error during area search:', error);
|
||||||
alert('An error occurred during the search.');
|
alert('An error occurred during the search.');
|
||||||
@@ -554,6 +555,20 @@ function Menu({data, duration, setDuration, end, setEnd, slider, setSlider, subm
|
|||||||
setSubmenu(false);
|
setSubmenu(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const mergeSearchResults = (index) => {
|
||||||
|
const newResults = [...searchResults];
|
||||||
|
const item1 = newResults[index];
|
||||||
|
const item2 = newResults[index + 1];
|
||||||
|
|
||||||
|
const mergedItem = {
|
||||||
|
start: item2.start,
|
||||||
|
end: item1.end,
|
||||||
|
};
|
||||||
|
|
||||||
|
newResults.splice(index, 2, mergedItem);
|
||||||
|
setSearchResults(newResults);
|
||||||
|
};
|
||||||
|
|
||||||
const range = parseSlider(end, duration, slider);
|
const range = parseSlider(end, duration, slider);
|
||||||
const startDate = moment(end).subtract(...duration.delta);
|
const startDate = moment(end).subtract(...duration.delta);
|
||||||
|
|
||||||
@@ -722,9 +737,7 @@ function Menu({data, duration, setDuration, end, setEnd, slider, setSlider, subm
|
|||||||
<div ref={scrollContainerRef} className="search-results-container">
|
<div ref={scrollContainerRef} className="search-results-container">
|
||||||
{searchResults.length > 0 ? (
|
{searchResults.length > 0 ? (
|
||||||
(() => {
|
(() => {
|
||||||
const sortedResults = [...searchResults].sort((a, b) => b.start - a.start);
|
const groupedResults = searchResults.reduce((acc, result) => {
|
||||||
|
|
||||||
const groupedResults = sortedResults.reduce((acc, result) => {
|
|
||||||
const groupKey = moment.unix(result.start).format('YYYY');
|
const groupKey = moment.unix(result.start).format('YYYY');
|
||||||
if (!acc[groupKey]) {
|
if (!acc[groupKey]) {
|
||||||
acc[groupKey] = [];
|
acc[groupKey] = [];
|
||||||
@@ -747,15 +760,34 @@ function Menu({data, duration, setDuration, end, setEnd, slider, setSlider, subm
|
|||||||
.map(([groupKey, results]) => (
|
.map(([groupKey, results]) => (
|
||||||
<div key={groupKey}>
|
<div key={groupKey}>
|
||||||
<h3 className="search-results-group-header">{groupKey}</h3>
|
<h3 className="search-results-group-header">{groupKey}</h3>
|
||||||
{results.map((result, index) => (
|
{results.map((result, indexInYear) => {
|
||||||
|
const absoluteIndex = searchResults.findIndex(r => r.start === result.start && r.end === result.end);
|
||||||
|
const isLastResultOverall = absoluteIndex === searchResults.length - 1;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="search-result-row" key={`${result.start}-${result.end}`}>
|
||||||
|
<div className="merge-button-wrapper">
|
||||||
|
{!isLastResultOverall && (
|
||||||
|
<button
|
||||||
|
className="merge-button"
|
||||||
|
title="Merge with next item"
|
||||||
|
onClick={() => mergeSearchResults(absoluteIndex)}
|
||||||
|
>
|
||||||
|
↓↑
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="search-result-button-wrapper">
|
||||||
<button
|
<button
|
||||||
key={index}
|
|
||||||
onClick={() => selectSearchResult(result)}
|
onClick={() => selectSearchResult(result)}
|
||||||
className={activeSearchResult && activeSearchResult.start === result.start && activeSearchResult.end === result.end ? 'active' : ''}
|
className={activeSearchResult && activeSearchResult.start === result.start && activeSearchResult.end === result.end ? 'active' : ''}
|
||||||
>
|
>
|
||||||
{formatShortTime(result.start)} - {formatShortTime(result.end)}
|
{formatShortTime(result.start)} - {formatShortTime(result.end)}
|
||||||
</button>
|
</button>
|
||||||
))}
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
));
|
));
|
||||||
})()
|
})()
|
||||||
|
|||||||
Reference in New Issue
Block a user