Files
mue/src/features/search/Search.jsx

150 lines
4.2 KiB
JavaScript

/* global chrome */
import variables from 'config/variables';
import { memo, useRef, useEffect, useState, useCallback } from 'react';
import { MdSearch, MdMic } from 'react-icons/md';
import { Tooltip } from 'components/Elements';
import { useT } from 'contexts';
import EventBus from 'utils/eventbus';
import './search.scss';
function Search() {
const t = useT();
const [microphone, setMicrophone] = useState(null);
const [classList] = useState(
localStorage.getItem('widgetStyle') === 'legacy' ? 'searchIcons old' : 'searchIcons',
);
const micIcon = useRef(null);
const startSpeechRecognition = useCallback(() => {
const voiceSearch = new window.webkitSpeechRecognition();
voiceSearch.start();
micIcon.current.classList.add('micActive');
const searchText = document.getElementById('searchtext');
voiceSearch.onresult = (event) => {
searchText.value = event.results[0][0].transcript;
};
voiceSearch.onend = () => {
micIcon.current.classList.remove('micActive');
if (searchText.value === '') {
return;
}
setTimeout(() => {
variables.stats.postEvent('feature', 'Voice search');
if (chrome && chrome.search && chrome.search.query) {
chrome.search
.query({
text: searchText.value,
disposition: 'CURRENT_TAB',
})
.catch((error) => {
console.error('Search API error:', error);
window.location.href = `https://www.google.com/search?q=${encodeURIComponent(searchText.value)}`;
});
} else {
window.location.href = `https://www.google.com/search?q=${encodeURIComponent(searchText.value)}`;
}
}, 1000);
};
}, [micIcon]);
const init = useCallback(() => {
if (localStorage.getItem('voiceSearch') === 'true') {
setMicrophone(
<button
className="navbarButton"
onClick={startSpeechRecognition}
ref={micIcon}
aria-label={t('common.microphone_search')}
>
<MdMic className="micIcon" />
</button>,
);
} else {
setMicrophone(null);
}
}, [startSpeechRecognition]);
useEffect(() => {
init();
if (localStorage.getItem('searchFocus') === 'true') {
const element = document.getElementById('searchtext');
if (element) {
element.focus();
}
}
const handleRefresh = (data) => {
if (data === 'search') {
init();
}
};
EventBus.on('refresh', handleRefresh);
return () => {
EventBus.off('refresh', handleRefresh);
};
}, [init]);
function searchButton(e) {
e.preventDefault();
const value = e.target.value || document.getElementById('searchtext').value || 'mue fast';
variables.stats.postEvent('feature', 'Search');
if (chrome && chrome.search && chrome.search.query) {
chrome.search
.query({
text: value,
disposition: 'CURRENT_TAB',
})
.catch((error) => {
console.error('Search API error:', error);
window.location.href = `https://www.google.com/search?q=${encodeURIComponent(value)}`;
});
} else {
window.location.href = `https://www.google.com/search?q=${encodeURIComponent(value)}`;
}
}
return (
<div className="searchComponents">
<div className="searchMain">
<div className={classList}>
<Tooltip title={t('modals.main.settings.sections.search.voice_search')}>
{microphone}
</Tooltip>
</div>
<form onSubmit={searchButton} className="searchBar">
<div className={classList}>
<Tooltip title={t('widgets.search')}>
<button
className="navbarButton"
onClick={searchButton}
aria-label={t('common.search_label')}
>
<MdSearch />
</button>
</Tooltip>
</div>
<input
type="text"
placeholder={t('widgets.search')}
id="searchtext"
className="searchInput"
/>
</form>
</div>
</div>
);
}
const MemoizedSearch = memo(Search);
export { MemoizedSearch as default, MemoizedSearch as Search };