diff --git a/extensions/react-widget/package.json b/extensions/react-widget/package.json index 554b2438..12a66939 100644 --- a/extensions/react-widget/package.json +++ b/extensions/react-widget/package.json @@ -32,6 +32,7 @@ "scripts": { "build": "parcel build src/main.tsx --public-url ./", "build:react": "parcel build src/index.ts", + "serve": "parcel serve -p 3000", "dev": "parcel -p 3000", "test": "jest", "lint": "eslint", diff --git a/extensions/react-widget/src/components/SearchBar.tsx b/extensions/react-widget/src/components/SearchBar.tsx index e38b381c..07f29f26 100644 --- a/extensions/react-widget/src/components/SearchBar.tsx +++ b/extensions/react-widget/src/components/SearchBar.tsx @@ -6,10 +6,10 @@ import { getSearchResults } from '../requests/searchAPI' import { Result } from '@/types'; import MarkdownIt from 'markdown-it'; import DOMPurify from 'dompurify'; - +import { getOS } from '../utils/helper' const themes = { dark: { - bg: '#222327', + bg: '#000', text: '#fff', primary: { text: "#FAFAFA", @@ -47,6 +47,9 @@ const TextField = styled.input<{ inputWidth: string }>` outline: none; border: none; background-color: ${props => props.theme.secondary.bg}; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; transition: background-color 128ms linear; &:focus { outline: none; @@ -114,6 +117,7 @@ const ResultWrapper = styled.div` const Markdown = styled.div` line-height:20px; font-size: 12px; +word-break: break-all; pre { padding: 8px; width: 90%; @@ -197,12 +201,25 @@ const NoResults = styled.div` font-size: 1rem; color: #888; `; +const InfoButton = styled.button` + padding: 10px 4px 10px 4px; + display: block; + width: 100%; + color: inherit; + border-radius: 6px; + background-color: ${(props) => props.theme.bg}; + text-align: center; + font-size: 14px; + margin-bottom: 8px; + border:1px solid ${(props) => props.theme.secondary.text}; + +` export const SearchBar = ({ apiKey = "74039c6d-bff7-44ce-ae55-2973cbf13837", apiHost = "https://gptcloud.arc53.com", theme = "dark", placeholder = "Search or Ask AI...", - width = "240px" + width = "256px" }: SearchBarProps) => { const [input, setInput] = React.useState(""); const [loading, setLoading] = React.useState(false); @@ -213,6 +230,14 @@ export const SearchBar = ({ const [results, setResults] = React.useState([]); const debounceTimeout = React.useRef(null); const abortControllerRef = React.useRef(null) + const browserOS = getOS(); + const getKeyboardInstruction = () => { + if (browserOS === 'linux' || browserOS === 'win') + return "Ctrl K" + else if (browserOS === 'mac') + return "⌘ K" + else return "Enter" + } React.useEffect(() => { const handleClickOutside = (event: MouseEvent) => { if ( @@ -258,7 +283,11 @@ export const SearchBar = ({ }, [input]) const handleKeyDown = (event: React.KeyboardEvent) => { - if (event.ctrlKey && event.key === 'k') { + if ( + ((browserOS === 'win' || browserOS === 'linux') && event.ctrlKey && event.key === 'k') || + (browserOS === 'mac' && event.metaKey && event.key === 'k') || + ((browserOS === 'android' || browserOS === 'ios' || browserOS === 'other') && event.key === 'Enter') + ) { event.preventDefault(); setIsWidgetOpen(true); } @@ -272,10 +301,12 @@ export const SearchBar = ({
setIsResultVisible(true)} ref={inputRef} + onSubmit={() => setIsWidgetOpen(true)} onKeyDown={(e) => handleKeyDown(e)} placeholder={placeholder} value={input} @@ -284,6 +315,7 @@ export const SearchBar = ({ { input.length > 0 && isResultVisible && ( + {`Press ${getKeyboardInstruction()} to Ask the AI`} {!loading ? (results.length > 0 ? results.map((res) => { @@ -298,7 +330,7 @@ export const SearchBar = ({ {res.title} @@ -313,7 +345,9 @@ export const SearchBar = ({ ) } - Ctrl K + + {getKeyboardInstruction()} + { + const platform = window.navigator.platform; + const userAgent = window.navigator.userAgent || window.navigator.vendor; + + if (/Mac/i.test(platform)) { + return 'mac'; + } + + if (/Win/i.test(platform)) { + return 'win'; + } + + if (/Linux/i.test(platform) && !/Android/i.test(userAgent)) { + return 'linux'; + } + + if (/Android/i.test(userAgent)) { + return 'android'; + } + + if (/iPhone|iPad|iPod/i.test(userAgent)) { + return 'ios'; + } + + return 'other'; + }; + \ No newline at end of file