From 4ee6bd44d1d3572923a68563196c4550c30b466a Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Wed, 21 May 2025 01:26:34 +0530 Subject: [PATCH 1/4] (feat:glassy) search widget --- .../react-widget/src/components/SearchBar.tsx | 167 ++++++++++++------ 1 file changed, 111 insertions(+), 56 deletions(-) diff --git a/extensions/react-widget/src/components/SearchBar.tsx b/extensions/react-widget/src/components/SearchBar.tsx index c647991f..8efb0313 100644 --- a/extensions/react-widget/src/components/SearchBar.tsx +++ b/extensions/react-widget/src/components/SearchBar.tsx @@ -7,16 +7,17 @@ import { Result } from '@/types'; import MarkdownIt from 'markdown-it'; import { getOS, processMarkdownString } from '../utils/helper'; import DOMPurify from 'dompurify'; -import { - CodeIcon, +import { + CodeIcon, TextAlignLeftIcon, HeadingIcon, - ReaderIcon, - ListBulletIcon, - QuoteIcon + ReaderIcon, + ListBulletIcon, + QuoteIcon } from '@radix-ui/react-icons'; const themes = { dark: { + name: 'dark', bg: '#202124', text: '#EDEDED', primary: { @@ -29,6 +30,7 @@ const themes = { } }, light: { + name: 'light', bg: '#EAEAEA', text: '#171717', primary: { @@ -49,10 +51,10 @@ const GlobalStyle = createGlobalStyle` `; const loadGeistFont = () => { - const link = document.createElement('link'); - link.href = 'https://fonts.googleapis.com/css2?family=Geist:wght@100..900&display=swap'; - link.rel = 'stylesheet'; - document.head.appendChild(link); + const link = document.createElement('link'); + link.href = 'https://fonts.googleapis.com/css2?family=Geist:wght@100..900&display=swap'; + link.rel = 'stylesheet'; + document.head.appendChild(link); }; const Main = styled.div` @@ -81,12 +83,27 @@ const Container = styled.div` position: relative; display: inline-block; ` +const SearchOverlay = styled.div` + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: #0000001A; + backdrop-filter: blur(8px); + -webkit-backdrop-filter: blur(8px); + z-index: 99; +`; + + const SearchResults = styled.div` position: fixed; display: flex; flex-direction: column; - background-color: ${props => props.theme.primary.bg}; - border: 1px solid ${props => props.theme.bg}; + background-color: ${props => props.theme.name === 'dark' ? + 'rgba(0, 0, 0, 0.15)' : + 'rgba(255, 255, 255, 0.4)'}; + border: 1px solid rgba(255, 255, 255, 0.18); border-radius: 15px; padding: 8px 0px 8px 0px; width: 792px; @@ -97,8 +114,12 @@ const SearchResults = styled.div` top: 50%; transform: translate(-50%, -50%); color: ${props => props.theme.primary.text}; - box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1), 0 2px 4px rgba(0, 0, 0, 0.1); - backdrop-filter: blur(16px); + + box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.37); + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); + border-radius: 10px; + box-sizing: border-box; @media only screen and (max-width: 768px) { @@ -142,6 +163,33 @@ const ContentWrapper = styled.div` flex-direction: column; gap: 12px; `; + + + +const ResultWrapper = styled.div` + display: flex; + align-items: flex-start; + width: 100%; + box-sizing: border-box; + padding: 8px 16px; + cursor: pointer; + background-color: transparent; + font-family: 'Geist', sans-serif; + border-radius: 8px; + + word-wrap: break-word; + overflow-wrap: break-word; + word-break: break-word; + white-space: normal; + overflow: hidden; + text-overflow: ellipsis; + + &:hover { + backdrop-filter: blur(8px); + -webkit-backdrop-filter: blur(8px); + } +`; + const Content = styled.div` display: flex; margin-left: 8px; @@ -151,9 +199,10 @@ const Content = styled.div` font-size: 15px; color: ${props => props.theme.primary.text}; line-height: 1.6; - border-left: 2px solid #585858; + border-left: 2px solid ${props => props.theme.primary.text}CC; overflow: hidden; -` + +`; const ContentSegment = styled.div` display: flex; align-items: flex-start; @@ -165,29 +214,6 @@ const ContentSegment = styled.div` text-overflow: ellipsis; ` -const ResultWrapper = styled.div` - display: flex; - align-items: flex-start; - width: 100%; - box-sizing: border-box; - padding: 8px 16px; - cursor: pointer; - background-color: ${props => props.theme.primary.bg}; - font-family: 'Geist', sans-serif; - transition: background-color 0.2s; - border-radius: 8px; - - word-wrap: break-word; - overflow-wrap: break-word; - word-break: break-word; - white-space: normal; - overflow: hidden; - text-overflow: ellipsis; - - &:hover { - background-color: ${props => props.theme.bg}; - } -` const Markdown = styled.div` line-height:18px; font-size: 11px; @@ -280,7 +306,8 @@ const NoResults = styled.div` margin-top: 2rem; text-align: center; font-size: 14px; - color: #888; + color: ${props => props.theme.name === 'dark' ? '#E0E0E0' : '#505050'}; + font-weight: 500; `; const AskAIButton = styled.button` display: flex; @@ -293,25 +320,39 @@ const AskAIButton = styled.button` height: 50px; padding: 8px 24px; border: none; - border-radius: 6px; - background-color: ${props => props.theme.bg}; + border-radius: 8px; color: ${props => props.theme.text}; cursor: pointer; - transition: background-color 0.2s, box-shadow 0.2s; font-size: 16px; + backdrop-filter: blur(16px); + -webkit-backdrop-filter: blur(16px); + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05); + border: 1px solid ${props => props.theme.name === 'dark' ? + 'rgba(255, 255, 255, 0.2)' : + 'rgba(0, 0, 0, 0.1)'}; + background-color: ${props => props.theme.name === 'dark' ? + 'rgba(255, 255, 255, 0.05)' : + 'rgba(0, 0, 0, 0.03)'}; // Very subtle background for light theme &:hover { - opacity: 0.8; + backdrop-filter: blur(20px); + -webkit-backdrop-filter: blur(20px); + background-color: ${props => props.theme.name === 'dark' ? + 'rgba(255, 255, 255, 0.1)' : + 'rgba(0, 0, 0, 0.06)'}; // Subtle hover effect for light theme } -` +`; + const SearchHeader = styled.div` display: flex; align-items: center; gap: 8px; margin-bottom: 12px; padding-bottom: 12px; - border-bottom: 1px solid ${props => props.theme.bg}; -` + border-bottom: 1px solid ${props => props.theme.name === 'dark' ? '#FFFFFF24' : 'rgba(0, 0, 0, 0.14)'}; +`; + + const TextField = styled.input` width: calc(100% - 32px); @@ -327,8 +368,15 @@ const TextField = styled.input` &:focus { border-color: none; } + + &::placeholder { + color: #8F8F8F !important; + opacity: 100%; /* Force opacity to ensure placeholder is visible */ + } ` + + const EscapeInstruction = styled.kbd` display: flex; align-items: center; @@ -337,17 +385,21 @@ const EscapeInstruction = styled.kbd` padding: 4px 8px; border-radius: 4px; background-color: transparent; - border: 1px solid ${props => props.theme.secondary.text}; - color: ${props => props.theme.text}; + border: 1px solid ${props => props.theme.name === 'dark' ? + 'rgba(237, 237, 237, 0.6)' : + 'rgba(23, 23, 23, 0.6)'}; + color: ${props => props.theme.name === 'dark' ? '#EDEDED' : '#171717'}; font-size: 12px; font-family: 'Geist', sans-serif; white-space: nowrap; cursor: pointer; width: fit-content; - &:hover { - background-color: rgba(255, 255, 255, 0.1); - } -` + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; +`; + + export const SearchBar = ({ apiKey = "74039c6d-bff7-44ce-ae55-2973cbf13837", apiHost = "https://gptcloud.arc53.com", @@ -367,7 +419,7 @@ export const SearchBar = ({ const abortControllerRef = React.useRef(null); const browserOS = getOS(); const isTouch = 'ontouchstart' in window; - + const getKeyboardInstruction = () => { if (isResultVisible) return "Enter"; return browserOS === 'mac' ? '⌘ + K' : 'Ctrl + K'; @@ -394,7 +446,7 @@ export const SearchBar = ({ } }; - + document.addEventListener('mousedown', handleClickOutside); document.addEventListener('keydown', handleKeyDown); return () => { @@ -462,6 +514,8 @@ export const SearchBar = ({ { isResultVisible && ( + <> + setIsResultVisible(false)} /> - DocsGPT + ) } { From 7432e551f93ca35f46c9305880f3620e1c10dc48 Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Wed, 21 May 2025 01:40:03 +0530 Subject: [PATCH 2/4] (fix/loader) drop on empty input --- extensions/react-widget/src/components/SearchBar.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/extensions/react-widget/src/components/SearchBar.tsx b/extensions/react-widget/src/components/SearchBar.tsx index 8efb0313..46243790 100644 --- a/extensions/react-widget/src/components/SearchBar.tsx +++ b/extensions/react-widget/src/components/SearchBar.tsx @@ -458,26 +458,27 @@ export const SearchBar = ({ React.useEffect(() => { if (!input) { setResults([]); + setLoading(false); return; } setLoading(true); if (debounceTimeout.current) { clearTimeout(debounceTimeout.current); } - + if (abortControllerRef.current) { abortControllerRef.current.abort(); } const abortController = new AbortController(); abortControllerRef.current = abortController; - + debounceTimeout.current = setTimeout(() => { getSearchResults(input, apiKey, apiHost, abortController.signal) .then((data) => setResults(data)) .catch((err) => !abortController.signal.aborted && console.log(err)) .finally(() => setLoading(false)); }, 500); - + return () => { abortController.abort(); clearTimeout(debounceTimeout.current ?? undefined); From ec50650dfa6b1cbad51d826219ba4b3c7fc5d0c8 Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Wed, 21 May 2025 02:00:47 +0530 Subject: [PATCH 3/4] (fix/searchwidget) prominent placeholder, sleek spinner --- .../react-widget/src/components/SearchBar.tsx | 66 ++++++++++--------- 1 file changed, 34 insertions(+), 32 deletions(-) diff --git a/extensions/react-widget/src/components/SearchBar.tsx b/extensions/react-widget/src/components/SearchBar.tsx index 46243790..1cfcee9a 100644 --- a/extensions/react-widget/src/components/SearchBar.tsx +++ b/extensions/react-widget/src/components/SearchBar.tsx @@ -46,7 +46,8 @@ const themes = { const GlobalStyle = createGlobalStyle` .highlight { - color:#007EE6; + color: ${props => props.theme.name === 'dark' ? '#4B9EFF' : '#0066CC'}; + font-weight: 500; } `; @@ -285,8 +286,8 @@ const Toolkit = styled.kbd` ` const Loader = styled.div` margin: 2rem auto; - border: 4px solid ${props => props.theme.secondary.text}; - border-top: 4px solid ${props => props.theme.primary.bg}; + border: 4px solid ${props => props.theme.name === 'dark' ? 'rgba(255, 255, 255, 0.2)' : 'rgba(0, 0, 0, 0.1)'}; + border-top: 4px solid ${props => props.theme.name === 'dark' ? '#FFFFFF' : props.theme.primary.bg}; border-radius: 50%; width: 12px; height: 12px; @@ -370,8 +371,9 @@ const TextField = styled.input` } &::placeholder { - color: #8F8F8F !important; + color: ${props => props.theme.name === 'dark' ? 'rgba(255, 255, 255, 0.6)' : 'rgba(0, 0, 0, 0.5)'} !important; opacity: 100%; /* Force opacity to ensure placeholder is visible */ + font-weight: 500; } ` @@ -456,34 +458,34 @@ export const SearchBar = ({ }, []); React.useEffect(() => { - if (!input) { - setResults([]); - setLoading(false); - return; - } - setLoading(true); - if (debounceTimeout.current) { - clearTimeout(debounceTimeout.current); - } - - if (abortControllerRef.current) { - abortControllerRef.current.abort(); - } - const abortController = new AbortController(); - abortControllerRef.current = abortController; - - debounceTimeout.current = setTimeout(() => { - getSearchResults(input, apiKey, apiHost, abortController.signal) - .then((data) => setResults(data)) - .catch((err) => !abortController.signal.aborted && console.log(err)) - .finally(() => setLoading(false)); - }, 500); - - return () => { - abortController.abort(); - clearTimeout(debounceTimeout.current ?? undefined); - }; - }, [input]) + if (!input) { + setResults([]); + setLoading(false); + return; + } + setLoading(true); + if (debounceTimeout.current) { + clearTimeout(debounceTimeout.current); + } + + if (abortControllerRef.current) { + abortControllerRef.current.abort(); + } + const abortController = new AbortController(); + abortControllerRef.current = abortController; + + debounceTimeout.current = setTimeout(() => { + getSearchResults(input, apiKey, apiHost, abortController.signal) + .then((data) => setResults(data)) + .catch((err) => !abortController.signal.aborted && console.log(err)) + .finally(() => setLoading(false)); + }, 500); + + return () => { + abortController.abort(); + clearTimeout(debounceTimeout.current ?? undefined); + }; +}, [input]) const handleKeyDown = (event: React.KeyboardEvent) => { if (event.key === 'Enter') { From d89e78c9ca59acf767f7d6e32e61404239e0f8b6 Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Wed, 21 May 2025 02:59:22 +0530 Subject: [PATCH 4/4] (feat:search) minor adjust --- .../react-widget/src/components/SearchBar.tsx | 64 ++----------------- 1 file changed, 4 insertions(+), 60 deletions(-) diff --git a/extensions/react-widget/src/components/SearchBar.tsx b/extensions/react-widget/src/components/SearchBar.tsx index 1cfcee9a..e84bcec3 100644 --- a/extensions/react-widget/src/components/SearchBar.tsx +++ b/extensions/react-widget/src/components/SearchBar.tsx @@ -4,7 +4,6 @@ import { WidgetCore } from './DocsGPTWidget'; import { SearchBarProps } from '@/types'; import { getSearchResults } from '../requests/searchAPI'; import { Result } from '@/types'; -import MarkdownIt from 'markdown-it'; import { getOS, processMarkdownString } from '../utils/helper'; import DOMPurify from 'dompurify'; import { @@ -117,8 +116,8 @@ const SearchResults = styled.div` color: ${props => props.theme.primary.text}; box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.37); - backdrop-filter: blur(12px); - -webkit-backdrop-filter: blur(12px); + backdrop-filter: blur(82px); + -webkit-backdrop-filter: blur(82px); border-radius: 10px; box-sizing: border-box; @@ -215,57 +214,6 @@ const ContentSegment = styled.div` text-overflow: ellipsis; ` -const Markdown = styled.div` -line-height:18px; -font-size: 11px; -white-space: pre-wrap; - pre { - padding: 8px; - width: 90%; - font-size: 11px; - border-radius: 6px; - overflow-x: auto; - background-color: #1B1C1F; - color: #fff ; - } - - h1,h2 { - font-size: 14px; - font-weight: 600; - color: ${(props) => props.theme.text}; - opacity: 0.8; - } - - - h3 { - font-size: 12px; - } - - p { - margin: 0px; - line-height: 1.35rem; - font-size: 11px; - } - - code:not(pre code) { - border-radius: 6px; - padding: 2px 2px; - margin: 2px; - font-size: 9px; - display: inline; - background-color: #646464; - color: #fff ; - } - img{ - max-width: 50%; - } - code { - overflow-x: auto; - } - a{ - color: #007ee6; - } -` const Toolkit = styled.kbd` position: absolute; right: 4px; @@ -327,20 +275,16 @@ const AskAIButton = styled.button` font-size: 16px; backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px); - box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05); - border: 1px solid ${props => props.theme.name === 'dark' ? - 'rgba(255, 255, 255, 0.2)' : - 'rgba(0, 0, 0, 0.1)'}; background-color: ${props => props.theme.name === 'dark' ? 'rgba(255, 255, 255, 0.05)' : - 'rgba(0, 0, 0, 0.03)'}; // Very subtle background for light theme + 'rgba(0, 0, 0, 0.03)'}; &:hover { backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px); background-color: ${props => props.theme.name === 'dark' ? 'rgba(255, 255, 255, 0.1)' : - 'rgba(0, 0, 0, 0.06)'}; // Subtle hover effect for light theme + 'rgba(0, 0, 0, 0.06)'}; } `;