diff --git a/extensions/react-widget/package-lock.json b/extensions/react-widget/package-lock.json
index de4c228d6..6d736c6f0 100644
--- a/extensions/react-widget/package-lock.json
+++ b/extensions/react-widget/package-lock.json
@@ -4860,9 +4860,9 @@
}
},
"node_modules/caniuse-lite": {
- "version": "1.0.30001625",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001625.tgz",
- "integrity": "sha512-4KE9N2gcRH+HQhpeiRZXd+1niLB/XNLAhSy4z7fI8EzcbcPoAqjNInxVHTiTwWfTIV4w096XG8OtCOCQQKPv3w==",
+ "version": "1.0.30001680",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001680.tgz",
+ "integrity": "sha512-rPQy70G6AGUMnbwS1z6Xg+RkHYPAi18ihs47GH0jcxIG7wArmPgY3XbS2sRdBbxJljp3thdT8BIqv9ccCypiPA==",
"funding": [
{
"type": "opencollective",
@@ -4876,7 +4876,8 @@
"type": "github",
"url": "https://github.com/sponsors/ai"
}
- ]
+ ],
+ "license": "CC-BY-4.0"
},
"node_modules/chalk": {
"version": "2.4.2",
diff --git a/extensions/react-widget/package.json b/extensions/react-widget/package.json
index a1097403a..554b2438d 100644
--- a/extensions/react-widget/package.json
+++ b/extensions/react-widget/package.json
@@ -32,7 +32,7 @@
"scripts": {
"build": "parcel build src/main.tsx --public-url ./",
"build:react": "parcel build src/index.ts",
- "dev": "parcel src/index.html -p 3000",
+ "dev": "parcel -p 3000",
"test": "jest",
"lint": "eslint",
"check": "tsc --noEmit",
diff --git a/extensions/react-widget/src/App.tsx b/extensions/react-widget/src/App.tsx
index ec9de47be..4bb24bae1 100644
--- a/extensions/react-widget/src/App.tsx
+++ b/extensions/react-widget/src/App.tsx
@@ -1,11 +1,11 @@
import React from "react"
import {DocsGPTWidget} from "./components/DocsGPTWidget"
-const App = () => {
+import {SearchBar} from "./components/SearchBar"
+export const App = () => {
return (
+
)
-}
-
-export default App
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/extensions/react-widget/src/components/DocsGPTWidget.tsx b/extensions/react-widget/src/components/DocsGPTWidget.tsx
index 1baa4c626..b9ee8acc1 100644
--- a/extensions/react-widget/src/components/DocsGPTWidget.tsx
+++ b/extensions/react-widget/src/components/DocsGPTWidget.tsx
@@ -1,9 +1,9 @@
"use client";
import React, { useRef } from 'react'
import DOMPurify from 'dompurify';
-import styled, { keyframes, createGlobalStyle } from 'styled-components';
+import styled, { keyframes,css } from 'styled-components';
import { PaperPlaneIcon, RocketIcon, ExclamationTriangleIcon, Cross2Icon } from '@radix-ui/react-icons';
-import { FEEDBACK, MESSAGE_TYPE, Query, Status, WidgetProps } from '../types/index';
+import { FEEDBACK, MESSAGE_TYPE, Query, Status, WidgetCoreProps, WidgetProps } from '../types/index';
import { fetchAnswerStreaming, sendFeedback } from '../requests/streamingApi';
import { ThemeProvider } from 'styled-components';
import Like from "../assets/like.svg"
@@ -49,38 +49,8 @@ const sizesConfig = {
maxHeight: custom.maxHeight || '70vh',
}),
};
-
-const Overlay = styled.div`
- position: fixed;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- background-color: rgba(0, 0, 0, 0.5);
- z-index: 999;
- transition: opacity 0.5s;
-`
-const WidgetContainer = styled.div<{ modal?: boolean, isOpen?: boolean }>`
- all: initial;
- position: fixed;
- right: ${props => props.modal ? '50%' : '10px'};
- bottom: ${props => props.modal ? '50%' : '10px'};
- z-index: 1000;
- display: none;
- transform-origin:100% 100%;
- &.open {
- animation: createBox 250ms cubic-bezier(0.25, 0.1, 0.25, 1) forwards;
- }
- &.close {
- animation: closeBox 250ms cubic-bezier(0.25, 0.1, 0.25, 1) forwards;
- }
- ${props => props.modal &&
- "transform : translate(50%,50%);"
- }
- align-items: center;
- text-align: left;
- @keyframes createBox {
- 0% {
+const createBox = keyframes`
+ 0% {
transform: scale(0.6);
}
90% {
@@ -89,10 +59,9 @@ const WidgetContainer = styled.div<{ modal?: boolean, isOpen?: boolean }>`
100% {
transform: scale(1);
}
- }
-
- @keyframes closeBox {
- 0% {
+`
+const closeBox = keyframes`
+ 0% {
transform: scale(1);
}
10% {
@@ -101,32 +70,9 @@ const WidgetContainer = styled.div<{ modal?: boolean, isOpen?: boolean }>`
100% {
transform: scale(0.6);
}
- }
-`;
-const StyledContainer = styled.div<{ isOpen: boolean }>`
- all: initial;
- max-height: ${(props) => props.theme.dimensions.maxHeight};
- max-width: ${(props) => props.theme.dimensions.maxWidth};
- position: relative;
- flex-direction: column;
- justify-content: space-between;
- bottom: 0;
- left: 0;
- background-color: ${(props) => props.theme.primary.bg};
- font-family: sans-serif;
- display: flex;
- border-radius: 12px;
- box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05), 0 2px 4px rgba(0, 0, 0, 0.1);
- padding: 26px 26px 0px 26px;
- animation: ${({ isOpen, theme }) =>
- theme.dimensions.size === 'large'
- ? isOpen
- ? 'fadeIn 150ms ease-in forwards'
- : 'fadeOut 150ms ease-in forwards'
- : isOpen
- ? 'openContainer 150ms ease-in forwards'
- : 'closeContainer 250ms ease-in forwards'};
- @keyframes openContainer {
+`
+
+const openContainer = keyframes`
0% {
width: 200px;
height: 100px;
@@ -135,10 +81,9 @@ const StyledContainer = styled.div<{ isOpen: boolean }>`
width: ${(props) => props.theme.dimensions.width};
height: ${(props) => props.theme.dimensions.height};
border-radius: 12px;
- }
- }
- @keyframes closeContainer {
- 0% {
+ }`
+const closeContainer = keyframes`
+ 0% {
width: ${(props) => props.theme.dimensions.width};
height: ${(props) => props.theme.dimensions.height};
border-radius: 12px;
@@ -147,9 +92,9 @@ const StyledContainer = styled.div<{ isOpen: boolean }>`
width: 200px;
height: 100px;
}
- }
- @keyframes fadeIn {
- from {
+`
+const fadeIn = keyframes`
+ from {
opacity: 0;
width: ${(props) => props.theme.dimensions.width};
height: ${(props) => props.theme.dimensions.height};
@@ -161,9 +106,10 @@ const StyledContainer = styled.div<{ isOpen: boolean }>`
width: ${(props) => props.theme.dimensions.width};
height: ${(props) => props.theme.dimensions.height};
}
- }
- @keyframes fadeOut {
- from {
+`
+
+const fadeOut = keyframes`
+ from {
opacity: 1;
width: ${(props) => props.theme.dimensions.width};
height: ${(props) => props.theme.dimensions.height};
@@ -174,13 +120,80 @@ const StyledContainer = styled.div<{ isOpen: boolean }>`
width: ${(props) => props.theme.dimensions.width};
height: ${(props) => props.theme.dimensions.height};
}
+`
+const scaleAnimation = keyframes`
+ from {
+ transform: scale(1.2);
+ }
+ to {
+ transform: scale(1);
+ }
+`
+const Overlay = styled.div`
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background-color: rgba(0, 0, 0, 0.5);
+ z-index: 999;
+ transition: opacity 0.5s;
+`
+
+
+const WidgetContainer = styled.div<{ modal?: boolean, isOpen?: boolean }>`
+ all: initial;
+ position: fixed;
+ right: ${props => props.modal ? '50%' : '10px'};
+ bottom: ${props => props.modal ? '50%' : '10px'};
+ z-index: 1001;
+ transform-origin:100% 100%;
+ display: block;
+ &.modal{
+ transform : translate(50%,50%);
+ }
+ &.open {
+ animation: css ${createBox} 250ms cubic-bezier(0.25, 0.1, 0.25, 1) forwards;
+ }
+ &.close {
+ animation: css ${closeBox} 250ms cubic-bezier(0.25, 0.1, 0.25, 1) forwards;
}
+ align-items: center;
+ text-align: left;
+`;
+
+const StyledContainer = styled.div<{ isOpen: boolean }>`
+ all: initial;
+ max-height: ${(props) => props.theme.dimensions.maxHeight};
+ max-width: ${(props) => props.theme.dimensions.maxWidth};
+ width: ${(props) => props.theme.dimensions.width};
+ height: ${(props) => props.theme.dimensions.height} ;
+ position: relative;
+ flex-direction: column;
+ justify-content: space-between;
+ bottom: 0;
+ left: 0;
+ background-color: ${(props) => props.theme.primary.bg};
+ font-family: sans-serif;
+ display: flex;
+ border-radius: 12px;
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05), 0 2px 4px rgba(0, 0, 0, 0.1);
+ padding: 26px 26px 0px 26px;
+ animation: ${({ isOpen, theme }) =>
+ theme.dimensions.size === 'large'
+ ? isOpen
+ ? css `${fadeIn} 150ms ease-in forwards`
+ : css ` ${fadeOut} 150ms ease-in forwards`
+ : isOpen
+ ? css `${openContainer} 150ms ease-in forwards`
+ : css `${closeContainer} 250ms ease-in forwards`};
@media only screen and (max-width: 768px) {
max-height: 100vh;
max-width: 80vw;
overflow: auto;
}
`;
+
const FloatingButton = styled.div<{ bgcolor: string, hidden: boolean, isAnimatingButton: boolean }>`
position: fixed;
display: ${props => props.hidden ? "none" : "flex"};
@@ -198,7 +211,7 @@ const FloatingButton = styled.div<{ bgcolor: string, hidden: boolean, isAnimatin
background: ${props => props.bgcolor};
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
cursor: pointer;
- animation: ${props => props.isAnimatingButton ? 'scaleAnimation 200ms forwards' : 'none'};
+ animation: ${props => props.isAnimatingButton ? css `${scaleAnimation} 200ms forwards` : 'none'};
&:hover {
transform: scale(1.1);
transition: transform 0.2s ease-in-out;
@@ -206,15 +219,6 @@ const FloatingButton = styled.div<{ bgcolor: string, hidden: boolean, isAnimatin
&:not(:hover) {
transition: transform 0.2s ease-in-out;
}
-
- @keyframes scaleAnimation {
- from {
- transform: scale(1.2);
- }
- to {
- transform: scale(1);
- }
- }
`;
const CancelButton = styled.button`
cursor: pointer;
@@ -478,7 +482,47 @@ const Hero = ({ title, description, theme }: { title: string, description: strin
);
};
-export const DocsGPTWidget = ({
+export const DocsGPTWidget = (props: WidgetProps) => {
+
+ const {
+ buttonIcon = 'https://d3dg1063dc54p9.cloudfront.net/widget/chat.svg',
+ buttonText = 'Ask a question',
+ buttonBg = 'linear-gradient(to bottom right, #5AF0EC, #E80D9D)',
+ defaultOpen = false,
+ ...coreProps
+ } = props
+
+ const [open, setOpen] = React.useState(defaultOpen);
+ const [isAnimatingButton, setIsAnimatingButton] = React.useState(false);
+ const [isFloatingButtonVisible, setIsFloatingButtonVisible] = React.useState(true);
+
+ React.useEffect(() => {
+ if (isFloatingButtonVisible)
+ setTimeout(() => setIsAnimatingButton(true), 250);
+ return () => {
+ setIsAnimatingButton(false)
+ }
+ }, [isFloatingButtonVisible])
+
+ const handleClose = () => {
+ setIsFloatingButtonVisible(true);
+ setOpen(false);
+ };
+ const handleOpen = () => {
+ setOpen(true);
+ setIsFloatingButtonVisible(false);
+ }
+ return (
+ <>
+
+
+ {buttonText}
+
+
+ >
+ )
+}
+export const WidgetCore = ({
apiHost = 'https://gptcloud.arc53.com',
apiKey = '82962c9a-aa77-4152-94e5-a4f84fd44c6a',
avatar = 'https://d3dg1063dc54p9.cloudfront.net/cute-docsgpt.png',
@@ -488,25 +532,37 @@ export const DocsGPTWidget = ({
heroDescription = 'This chatbot is built with DocsGPT and utilises GenAI, please review important information using sources.',
size = 'small',
theme = 'dark',
- buttonIcon = 'https://d3dg1063dc54p9.cloudfront.net/widget/chat.svg',
- buttonText = 'Ask a question',
- buttonBg = 'linear-gradient(to bottom right, #5AF0EC, #E80D9D)',
collectFeedback = true,
- deafultOpen = false
-}: WidgetProps) => {
- const [prompt, setPrompt] = React.useState('');
+ isOpen = false,
+ prefilledQuery = "",
+ handleClose
+}: WidgetCoreProps) => {
+ const [prompt, setPrompt] = React.useState("");
+ const [mounted, setMounted] = React.useState(false);
const [status, setStatus] = React.useState('idle');
- const [queries, setQueries] = React.useState([])
- const [conversationId, setConversationId] = React.useState(null)
- const [open, setOpen] = React.useState(deafultOpen)
+ const [queries, setQueries] = React.useState([]);
+ const [conversationId, setConversationId] = React.useState(null);
const [eventInterrupt, setEventInterrupt] = React.useState(false); //click or scroll by user while autoScrolling
- const [isAnimatingButton, setIsAnimatingButton] = React.useState(false);
- const [isFloatingButtonVisible, setIsFloatingButtonVisible] = React.useState(true);
- const isBubbleHovered = useRef(false)
- const widgetRef = useRef(null)
+
+ const isBubbleHovered = useRef(false);
const endMessageRef = React.useRef(null);
const md = new MarkdownIt();
+ React.useEffect(() => {
+ if (isOpen) {
+ setMounted(true); // Mount the component
+ setPrompt(prefilledQuery)
+ } else {
+ // Wait for animations before unmounting
+ const timeout = setTimeout(() => {
+ setMounted(false)
+ }, 250);
+ return () => clearTimeout(timeout);
+ }
+ }, [isOpen]);
+
+
+
const handleUserInterrupt = () => {
(status === 'loading') && setEventInterrupt(true);
}
@@ -615,135 +671,120 @@ export const DocsGPTWidget = ({
const handleImageError = (event: React.SyntheticEvent) => {
event.currentTarget.src = "https://d3dg1063dc54p9.cloudfront.net/cute-docsgpt.png";
};
- const handleClose = () => {
- setOpen(false);
- setTimeout(() => {
- if (widgetRef.current) widgetRef.current.style.display = "none";
- setIsFloatingButtonVisible(true);
- setIsAnimatingButton(true);
- setTimeout(() => setIsAnimatingButton(false), 200);
- }, 250)
- };
- const handleOpen = () => {
- setOpen(true);
- setIsFloatingButtonVisible(false);
- if (widgetRef.current)
- widgetRef.current.style.display = 'block'
- }
+
const dimensions =
typeof size === 'object' && 'custom' in size
? sizesConfig.getCustom(size.custom)
: sizesConfig[size];
-
+ if (!mounted) return null;
return (
- {open && size === 'large' &&
+ {isOpen && size === 'large' &&
}
-
-
- {buttonText}
-
-
- {
-
-
-
-
-
-
-
- {title}
- {description}
-
-
-
-
- {
- queries.length > 0 ? queries?.map((query, index) => {
- return (
-
- {
- query.prompt &&
-
- {query.prompt}
-
-
- }
- {
- query.response ? { isBubbleHovered.current = true }} type='ANSWER'>
-
-
-
-
- {collectFeedback &&
-
- handleFeedback("LIKE", index)} />
- handleFeedback("DISLIKE", index)} />
- }
-
- :
- {
- query.error ?
-
-
-
-
Network Error
- {query.error}
-
-
- :
-
- .
- .
- .
-
-
- }
-
- }
- )
- })
- :
- }
-
-
-
- setPrompt(event.target.value)}
- type='text' placeholder="Ask your question" />
-
-
-
-
-
- Powered by
- DocsGPT
-
-
- }
-
+ {(
+
+
+
+
+
+
+
+
+
+ {title}
+ {description}
+
+
+
+
+ {
+ queries.length > 0 ? queries?.map((query, index) => {
+ return (
+
+ {
+ query.prompt &&
+
+ {query.prompt}
+
+
+ }
+ {
+ query.response ? { isBubbleHovered.current = true }} type='ANSWER'>
+
+
+
+
+ {collectFeedback &&
+
+ handleFeedback("LIKE", index)} />
+ handleFeedback("DISLIKE", index)} />
+ }
+
+ :
+ {
+ query.error ?
+
+
+
+
Network Error
+ {query.error}
+
+
+ :
+
+ .
+ .
+ .
+
+
+ }
+
+ }
+ )
+ })
+ :
+ }
+
+
+
+ setPrompt(event.target.value)}
+ type='text' placeholder="Ask your question" />
+
+
+
+
+
+ Powered by
+ DocsGPT
+
+
+
+
+ )
+ }
)
}
\ No newline at end of file
diff --git a/extensions/react-widget/src/components/SearchBar.tsx b/extensions/react-widget/src/components/SearchBar.tsx
new file mode 100644
index 000000000..d1d3aa1aa
--- /dev/null
+++ b/extensions/react-widget/src/components/SearchBar.tsx
@@ -0,0 +1,270 @@
+import React from 'react'
+import styled, { keyframes, createGlobalStyle, ThemeProvider } from 'styled-components';
+import { WidgetCore } from './DocsGPTWidget';
+import { SearchBarProps } from '@/types';
+import { getSearchResults } from '../requests/searchAPI'
+import { Result } from '@/types';
+import MarkdownIt from 'markdown-it';
+import DOMPurify from 'dompurify';
+
+const themes = {
+ dark: {
+ bg: '#222327',
+ text: '#fff',
+ primary: {
+ text: "#FAFAFA",
+ bg: '#111111'
+ },
+ secondary: {
+ text: "#A1A1AA",
+ bg: "#38383b"
+ }
+ },
+ light: {
+ bg: '#fff',
+ text: '#000',
+ primary: {
+ text: "#222327",
+ bg: "#fff"
+ },
+ secondary: {
+ text: "#A1A1AA",
+ bg: "#F6F6F6"
+ }
+ }
+}
+
+const Main = styled.div`
+ all:initial;
+
+ font-family: sans-serif;
+`
+const TextField = styled.input<{ inputWidth: string }>`
+ padding: 6px 6px;
+ width: ${({ inputWidth }) => inputWidth};
+ border-radius: 8px;
+ display: inline;
+ color: ${props => props.theme.primary.text};
+ outline: none;
+ border: none;
+ background-color: ${props => props.theme.secondary.bg};
+
+ &:focus {
+ outline: none;
+ box-shadow: 0px 0px 0px 2px rgba(0, 109, 199);
+ background-color: ${props => props.theme.primary.bg};
+ }
+`
+
+const Container = styled.div`
+ position: relative;
+ display: inline-block;
+`
+const SearchResults = styled.div`
+ position: absolute;
+ display: block;
+ background-color: ${props => props.theme.primary.bg};
+ opacity: 90%;
+ border: 1px solid rgba(0, 0, 0, .1);
+ border-radius: 12px;
+ padding: 8px;
+ width: 576px;
+ z-index: 100;
+ height: 25vh;
+ overflow-y: auto;
+ top: 45px;
+ color: ${props => props.theme.primary.text};
+ scrollbar-color: lab(48.438 0 0 / 0.4) rgba(0, 0, 0, 0);
+ scrollbar-gutter: stable;
+ scrollbar-width: thin;
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05), 0 2px 4px rgba(0, 0, 0, 0.1);
+ backdrop-filter: blur(16px);
+ @media only screen and (max-width: 768px) {
+ max-height: 100vh;
+ max-width: 80vw;
+ overflow: auto;
+ }
+`
+const Title = styled.h3`
+ font-size: 14px;
+ color: ${props => props.theme.primary.text};
+ opacity: 0.8;
+ padding-bottom: 6px;
+ font-weight: 600;
+ text-transform: uppercase;
+ border-bottom: 1px solid ${(props) => props.theme.secondary.text};
+`
+const Content = styled.div`
+ font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
+`
+const ResultWrapper = styled.div`
+ padding: 4px 8px 4px 8px;
+ border-radius: 8px;
+ cursor: pointer;
+ &.contains-source:hover{
+ background-color: rgba(0, 92, 197, 0.15);
+ ${Title} {
+ color: rgb(0, 126, 230);
+ }
+ }
+`
+const Markdown = styled.div`
+line-height:20px;
+font-size: 12px;
+ pre {
+ padding: 8px;
+ width: 90%;
+ font-size: 12px;
+ border-radius: 6px;
+ overflow-x: auto;
+ background-color: #1B1C1F;
+ color: #fff ;
+ }
+
+ h1,h2 {
+ font-size: 16px;
+ font-weight: 600;
+ color: ${(props) => props.theme.text};
+ opacity: 0.8;
+ }
+
+
+ h3 {
+ font-size: 14px;
+ }
+
+ p {
+ margin: 0px;
+ line-height: 1.35rem;
+ font-size: 12px;
+ }
+
+ code:not(pre code) {
+ border-radius: 6px;
+ padding: 4px 4px;
+ font-size: 12px;
+ display: inline-block;
+ background-color: #646464;
+ color: #fff ;
+ }
+
+ code {
+ white-space: pre-wrap ;
+ overflow-wrap: break-word;
+ word-break: break-all;
+ }
+ a{
+ color: #007ee6;
+ }
+`
+const Toolkit = styled.kbd`
+ position: absolute;
+ right: 12px;
+ top: 4px;
+ background-color: ${(props) => props.theme.primary.bg};
+ color: ${(props) => props.theme.secondary.text};
+ font-weight: 600;
+ font-size: 10px;
+ padding: 3px;
+ border: 1px solid ${(props) => props.theme.secondary.text};
+ border-radius: 4px;
+`
+export const SearchBar = ({
+ apiKey = "74039c6d-bff7-44ce-ae55-2973cbf13837",
+ apiHost = "https://gptcloud.arc53.com",
+ theme = "dark",
+ placeholder = "Search or Ask AI...",
+ width = "240px"
+}: SearchBarProps) => {
+ const [input, setInput] = React.useState("");
+ const [isWidgetOpen, setIsWidgetOpen] = React.useState(false);
+ const inputRef = React.useRef(null);
+ const resultsRef = React.useRef(null);
+ const [isResultVisible, setIsResultVisible] = React.useState(true);
+ const [results, setResults] = React.useState([]);
+ React.useEffect(() => {
+ const handleClickOutside = (event: MouseEvent) => {
+ if (
+ resultsRef.current &&
+ !resultsRef.current.contains(event.target as Node)
+ ) {
+ setIsResultVisible(false);
+ }
+ };
+ document.addEventListener('mousedown', handleClickOutside);
+ return () => {
+ resultsRef.current && (resultsRef.current.style.display = 'block')
+ document.removeEventListener('mousedown', handleClickOutside);
+ };
+ }, [])
+ React.useEffect(() => {
+ input.length > 0 ?
+ getSearchResults(input, apiKey, apiHost)
+ .then((data) => setResults(data))
+ .catch((err) => console.log(err))
+ :
+ setResults([])
+ }, [input])
+
+ const handleKeyDown = (event: React.KeyboardEvent) => {
+ if (event.ctrlKey && event.key === 'k') {
+ event.preventDefault();
+ setIsWidgetOpen(true);
+ }
+ };
+ const handleClose = () => {
+ setIsWidgetOpen(false);
+ }
+ const md = new MarkdownIt();
+ return (
+
+
+
+ setIsResultVisible(true)}
+ ref={inputRef}
+ onKeyDown={(e) => handleKeyDown(e)}
+ placeholder={placeholder}
+ value={input}
+ onChange={(e) => setInput(e.target.value)}
+ />
+ {
+ input.length > 0 && results.length > 0 && isResultVisible && (
+
+ {results.map((res) => {
+ const containsSource = res.source !== 'local'
+ return (
+ {
+ if (!containsSource) return;
+ window.open(res.source, '_blank', 'noopener, noreferrer')
+ }}
+ className={containsSource ? "contains-source" : ""}>
+ {res.title}
+
+
+
+
+ )
+ })
+ }
+
+ )
+ }
+ Ctrl K
+
+
+
+
+ )
+}
\ No newline at end of file
diff --git a/extensions/react-widget/src/index.html b/extensions/react-widget/src/index.html
index 0f0710d5d..40eaad152 100644
--- a/extensions/react-widget/src/index.html
+++ b/extensions/react-widget/src/index.html
@@ -9,11 +9,11 @@
-
-
+ -->