docs: redesign search + re-introduce ai assistant in v2 docs (#8678)
* docs: redesign search + re-introduce ai assistant in v2 * change version in ui * show icon in case of error * fixes based on feedback
This commit is contained in:
@@ -4,6 +4,8 @@ import {
|
||||
usePageLoading,
|
||||
SearchProvider as UiSearchProvider,
|
||||
searchFiltersV2,
|
||||
AiAssistantIcon,
|
||||
AiAssistantProvider,
|
||||
} from "docs-ui"
|
||||
import { config } from "../config"
|
||||
import basePathUrl from "../utils/base-path-url"
|
||||
@@ -33,15 +35,14 @@ const SearchProvider = ({ children }: SearchProviderProps) => {
|
||||
items: [
|
||||
"Install Medusa with create-medusa-app",
|
||||
"What is an API route?",
|
||||
"What is a Module?",
|
||||
"What is a Workflow?",
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Developing with Medusa",
|
||||
items: [
|
||||
"How to create a Module",
|
||||
"How to create an API route",
|
||||
"How to create a module",
|
||||
"How to create a data model",
|
||||
"How to create an admin widget",
|
||||
],
|
||||
@@ -52,6 +53,28 @@ const SearchProvider = ({ children }: SearchProviderProps) => {
|
||||
),
|
||||
filterOptions: searchFiltersV2,
|
||||
}}
|
||||
commands={[
|
||||
{
|
||||
name: "ai-assistant",
|
||||
icon: <AiAssistantIcon />,
|
||||
component: (
|
||||
<AiAssistantProvider
|
||||
apiUrl={process.env.NEXT_PUBLIC_AI_ASSISTANT_URL || "temp"}
|
||||
websiteId={process.env.NEXT_PUBLIC_AI_WEBSITE_ID || "temp"}
|
||||
recaptchaSiteKey={
|
||||
process.env.NEXT_PUBLIC_AI_API_ASSISTANT_RECAPTCHA_SITE_KEY ||
|
||||
"temp"
|
||||
}
|
||||
/>
|
||||
),
|
||||
title: "AI Assistant",
|
||||
badge: {
|
||||
variant: "blue",
|
||||
badgeType: "shaded",
|
||||
children: "Beta",
|
||||
},
|
||||
},
|
||||
]}
|
||||
>
|
||||
{children}
|
||||
</UiSearchProvider>
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
"use client"
|
||||
|
||||
import { SearchProvider as UiSearchProvider, searchFiltersV2 } from "docs-ui"
|
||||
import {
|
||||
AiAssistantIcon,
|
||||
AiAssistantProvider,
|
||||
SearchProvider as UiSearchProvider,
|
||||
searchFiltersV2,
|
||||
} from "docs-ui"
|
||||
import { config } from "../config"
|
||||
|
||||
type SearchProviderProps = {
|
||||
@@ -47,6 +52,28 @@ const SearchProvider = ({ children }: SearchProviderProps) => {
|
||||
),
|
||||
filterOptions: searchFiltersV2,
|
||||
}}
|
||||
commands={[
|
||||
{
|
||||
name: "ai-assistant",
|
||||
icon: <AiAssistantIcon />,
|
||||
component: (
|
||||
<AiAssistantProvider
|
||||
apiUrl={process.env.NEXT_PUBLIC_AI_ASSISTANT_URL || "temp"}
|
||||
websiteId={process.env.NEXT_PUBLIC_AI_WEBSITE_ID || "temp"}
|
||||
recaptchaSiteKey={
|
||||
process.env.NEXT_PUBLIC_AI_API_ASSISTANT_RECAPTCHA_SITE_KEY ||
|
||||
"temp"
|
||||
}
|
||||
/>
|
||||
),
|
||||
title: "AI Assistant",
|
||||
badge: {
|
||||
variant: "blue",
|
||||
badgeType: "shaded",
|
||||
children: "Beta",
|
||||
},
|
||||
},
|
||||
]}
|
||||
initialDefaultFilters={["book"]}
|
||||
>
|
||||
{children}
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
"use client"
|
||||
|
||||
import { SearchProvider as UiSearchProvider, searchFiltersV2 } from "docs-ui"
|
||||
import {
|
||||
AiAssistantIcon,
|
||||
AiAssistantProvider,
|
||||
SearchProvider as UiSearchProvider,
|
||||
searchFiltersV2,
|
||||
} from "docs-ui"
|
||||
import { config } from "../config"
|
||||
|
||||
type SearchProviderProps = {
|
||||
@@ -28,15 +33,36 @@ const SearchProvider = ({ children }: SearchProviderProps) => {
|
||||
items: [
|
||||
"Medusa Configurations",
|
||||
"Commerce Modules",
|
||||
"Medusa JS Reference",
|
||||
"Medusa React Reference",
|
||||
"Workflows API Reference",
|
||||
"Medusa Workflows Reference",
|
||||
"Storefront Development",
|
||||
],
|
||||
},
|
||||
],
|
||||
checkInternalPattern: new RegExp(`^${config.baseUrl}/v2/resources/.*`),
|
||||
filterOptions: searchFiltersV2,
|
||||
}}
|
||||
commands={[
|
||||
{
|
||||
name: "ai-assistant",
|
||||
icon: <AiAssistantIcon />,
|
||||
component: (
|
||||
<AiAssistantProvider
|
||||
apiUrl={process.env.NEXT_PUBLIC_AI_ASSISTANT_URL || "temp"}
|
||||
websiteId={process.env.NEXT_PUBLIC_AI_WEBSITE_ID || "temp"}
|
||||
recaptchaSiteKey={
|
||||
process.env.NEXT_PUBLIC_AI_API_ASSISTANT_RECAPTCHA_SITE_KEY ||
|
||||
"temp"
|
||||
}
|
||||
/>
|
||||
),
|
||||
title: "AI Assistant",
|
||||
badge: {
|
||||
variant: "blue",
|
||||
badgeType: "shaded",
|
||||
children: "Beta",
|
||||
},
|
||||
},
|
||||
]}
|
||||
initialDefaultFilters={["resources"]}
|
||||
>
|
||||
{children}
|
||||
|
||||
@@ -49,6 +49,7 @@ const SearchProvider = ({ children }: SearchProviderProps) => {
|
||||
process.env.NEXT_PUBLIC_AI_API_ASSISTANT_RECAPTCHA_SITE_KEY ||
|
||||
"temp"
|
||||
}
|
||||
version="v1"
|
||||
/>
|
||||
),
|
||||
title: "AI Assistant",
|
||||
|
||||
@@ -1,13 +1,8 @@
|
||||
import React, { useState } from "react"
|
||||
import { ThreadType } from "../.."
|
||||
import clsx from "clsx"
|
||||
import {
|
||||
Button,
|
||||
type ButtonProps,
|
||||
ThumbDownIcon,
|
||||
ThumbUpIcon,
|
||||
} from "@/components"
|
||||
import { Check, SquareTwoStack } from "@medusajs/icons"
|
||||
import { Button, type ButtonProps } from "@/components"
|
||||
import { Check, SquareTwoStackMini, ThumbDown, ThumbUp } from "@medusajs/icons"
|
||||
import { useCopy } from "@/hooks"
|
||||
import { AiAssistantFeedbackType, useAiAssistant } from "@/providers"
|
||||
|
||||
@@ -43,21 +38,17 @@ export const AiAssistantThreadItemActions = ({
|
||||
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
"hidden md:flex gap-docs_0.25",
|
||||
"text-medusa-fg-muted",
|
||||
"sticky top-docs_1"
|
||||
)}
|
||||
className={clsx("hidden md:flex gap-docs_0.25", "text-medusa-fg-muted")}
|
||||
>
|
||||
<ActionButton onClick={handleCopy}>
|
||||
{isCopied ? <Check /> : <SquareTwoStack />}
|
||||
{isCopied ? <Check /> : <SquareTwoStackMini />}
|
||||
</ActionButton>
|
||||
{(feedback === null || feedback === "upvote") && (
|
||||
<ActionButton
|
||||
onClick={async () => handleFeedback("upvote", item.question_id)}
|
||||
className={clsx(feedback === "upvote" && "!text-medusa-fg-subtle")}
|
||||
>
|
||||
<ThumbUpIcon />
|
||||
<ThumbUp />
|
||||
</ActionButton>
|
||||
)}
|
||||
{(feedback === null || feedback === "downvote") && (
|
||||
@@ -65,7 +56,7 @@ export const AiAssistantThreadItemActions = ({
|
||||
onClick={async () => handleFeedback("downvote", item.question_id)}
|
||||
className={clsx(feedback === "downvote" && "!text-medusa-fg-subtle")}
|
||||
>
|
||||
<ThumbDownIcon />
|
||||
<ThumbDown />
|
||||
</ActionButton>
|
||||
)}
|
||||
</div>
|
||||
@@ -79,7 +70,7 @@ const ActionButton = ({ children, className, ...props }: ButtonProps) => {
|
||||
className={clsx(
|
||||
"text-medusa-fg-muted hover:text-medusa-fg-subtle",
|
||||
"hover:bg-medusa-bg-subtle-hover",
|
||||
"p-docs_0.125 rounded-docs_sm",
|
||||
"!p-[4.5px] rounded-docs_sm",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import clsx from "clsx"
|
||||
import React from "react"
|
||||
import { ThreadType } from ".."
|
||||
import { DotsLoading, MarkdownContent, QuestionMarkIcon } from "@/components"
|
||||
import { ExclamationCircle, Sparkles } from "@medusajs/icons"
|
||||
import { AiAssistantIcon, DotsLoading, MarkdownContent } from "@/components"
|
||||
import { AiAssistantThreadItemActions } from "./Actions"
|
||||
|
||||
export type AiAssistantThreadItemProps = {
|
||||
@@ -13,39 +12,37 @@ export const AiAssistantThreadItem = ({ item }: AiAssistantThreadItemProps) => {
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
"p-docs_1 flex justify-start gap-docs_1 items-start",
|
||||
"text-medusa-fg-subtle border-solid border-0 border-b",
|
||||
"border-medusa-border-base text-medium relative",
|
||||
item.type === "question" && "bg-medusa-bg-base",
|
||||
item.type === "answer" && "bg-medusa-bg-subtle"
|
||||
"p-docs_0.5 flex gap-docs_0.75 items-start",
|
||||
item.type === "question" && "justify-end",
|
||||
item.type === "answer" && "!pr-[20px]"
|
||||
)}
|
||||
>
|
||||
<span
|
||||
{item.type !== "question" && <AiAssistantIcon />}
|
||||
<div
|
||||
className={clsx(
|
||||
"border border-solid border-medusa-border-base",
|
||||
"rounded-docs_sm p-docs_0.125 bg-medusa-bg-component",
|
||||
"text-medusa-fg-muted flex"
|
||||
"txt-small text-medusa-fg-subtle",
|
||||
item.type === "question" && [
|
||||
"rounded-docs_xl bg-medusa-tag-neutral-bg",
|
||||
"px-docs_0.75 py-docs_0.5",
|
||||
],
|
||||
item.type !== "question" && "flex-1",
|
||||
item.type === "answer" && "text-pretty"
|
||||
)}
|
||||
>
|
||||
{item.type === "question" && <QuestionMarkIcon />}
|
||||
{item.type === "answer" && <Sparkles />}
|
||||
{item.type === "error" && <ExclamationCircle />}
|
||||
</span>
|
||||
<div className="md:max-w-[calc(100%-134px)] md:w-[calc(100%-134px)]">
|
||||
{item.type === "question" && <>{item.content}</>}
|
||||
{item.type === "answer" && (
|
||||
<>
|
||||
<div className="flex flex-col gap-docs_0.75">
|
||||
{!item.question_id && item.content.length === 0 && <DotsLoading />}
|
||||
<MarkdownContent>{item.content}</MarkdownContent>
|
||||
</>
|
||||
<MarkdownContent className="[&>*:last-child]:mb-0">
|
||||
{item.content}
|
||||
</MarkdownContent>
|
||||
{item.question_id && <AiAssistantThreadItemActions item={item} />}
|
||||
</div>
|
||||
)}
|
||||
{item.type === "error" && (
|
||||
<span className="text-medusa-fg-error">{item.content}</span>
|
||||
)}
|
||||
</div>
|
||||
{item.type === "answer" && item.question_id && (
|
||||
<AiAssistantThreadItemActions item={item} />
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -11,10 +11,9 @@ import {
|
||||
SearchHitGroupName,
|
||||
Tooltip,
|
||||
Link,
|
||||
AiAssistantIcon,
|
||||
} from "@/components"
|
||||
import { useAiAssistant, useSearch } from "@/providers"
|
||||
import { ArrowUturnLeft, XMarkMini } from "@medusajs/icons"
|
||||
import { ArrowUturnLeft } from "@medusajs/icons"
|
||||
import clsx from "clsx"
|
||||
import { useSearchNavigation } from "@/hooks"
|
||||
import { AiAssistantThreadItem } from "./ThreadItem"
|
||||
@@ -77,26 +76,50 @@ export const AiAssistant = () => {
|
||||
const [answer, setAnswer] = useState("")
|
||||
const [identifiers, setIdentifiers] = useState<IdentifierType | null>(null)
|
||||
const [loading, setLoading] = useState(false)
|
||||
const { getAnswer } = useAiAssistant()
|
||||
const { getAnswer, version } = useAiAssistant()
|
||||
const { setCommand } = useSearch()
|
||||
const inputRef = useRef<HTMLInputElement>(null)
|
||||
const contentRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
const suggestions: SearchSuggestionType[] = [
|
||||
{
|
||||
title: "FAQ",
|
||||
items: [
|
||||
"What is Medusa?",
|
||||
"How can I create an ecommerce store with Medusa?",
|
||||
"How can I build a marketplace with Medusa?",
|
||||
"How can I build subscription-based purchases with Medusa?",
|
||||
"How can I build digital products with Medusa?",
|
||||
"What can I build with Medusa?",
|
||||
"What is Medusa Admin?",
|
||||
"How do I configure the database in Medusa?",
|
||||
],
|
||||
},
|
||||
]
|
||||
const suggestions: SearchSuggestionType[] = useMemo(() => {
|
||||
return version === "v2"
|
||||
? [
|
||||
{
|
||||
title: "FAQ",
|
||||
items: [
|
||||
"What is Medusa?",
|
||||
"How can I create a module?",
|
||||
"How can I create a data model?",
|
||||
"How do I create a workflow?",
|
||||
"How can I extend a data model in the Product Module?",
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Recipes",
|
||||
items: [
|
||||
"How do I build a marketplace with Medusa?",
|
||||
"How do I build digital products with Medusa?",
|
||||
"How do I build subscription-based purchases with Medusa?",
|
||||
"What other recipes are available in the Medusa documentation?",
|
||||
],
|
||||
},
|
||||
]
|
||||
: [
|
||||
{
|
||||
title: "FAQ",
|
||||
items: [
|
||||
"What is Medusa?",
|
||||
"How can I create an ecommerce store with Medusa?",
|
||||
"How can I build a marketplace with Medusa?",
|
||||
"How can I build subscription-based purchases with Medusa?",
|
||||
"How can I build digital products with Medusa?",
|
||||
"What can I build with Medusa?",
|
||||
"What is Medusa Admin?",
|
||||
"How do I configure the database in Medusa?",
|
||||
],
|
||||
},
|
||||
]
|
||||
}, [version])
|
||||
|
||||
const handleSubmit = (selectedQuestion?: string) => {
|
||||
if (!selectedQuestion?.length && !question.length) {
|
||||
@@ -292,6 +315,22 @@ export const AiAssistant = () => {
|
||||
|
||||
return (
|
||||
<div className="h-full">
|
||||
<div className={clsx("px-docs_1 pt-docs_1")}>
|
||||
<Tooltip
|
||||
tooltipChildren={
|
||||
<>
|
||||
This site is protected by reCAPTCHA and the{" "}
|
||||
<Link href="https://policies.google.com/privacy">
|
||||
Google Privacy Policy
|
||||
</Link>{" "}
|
||||
and <Link href="https://policies.google.com/terms">ToS</Link>{" "}
|
||||
apply
|
||||
</>
|
||||
}
|
||||
>
|
||||
<Badge variant="neutral">AI Assistant</Badge>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div
|
||||
className={clsx(
|
||||
"flex gap-docs_1 px-docs_1 py-docs_0.75",
|
||||
@@ -302,7 +341,7 @@ export const AiAssistant = () => {
|
||||
<Button
|
||||
variant="transparent"
|
||||
onClick={() => setCommand(null)}
|
||||
className="text-medusa-fg-subtle p-[5px]"
|
||||
className="text-medusa-fg-muted p-[6.5px]"
|
||||
>
|
||||
<ArrowUturnLeft />
|
||||
</Button>
|
||||
@@ -311,7 +350,7 @@ export const AiAssistant = () => {
|
||||
onChange={(e) => setQuestion(e.target.value)}
|
||||
className={clsx(
|
||||
"bg-transparent border-0 focus:outline-none hover:!bg-transparent",
|
||||
"shadow-none flex-1 text-medusa-fg-base",
|
||||
"!shadow-none flex-1 text-medusa-fg-base",
|
||||
"disabled:!bg-transparent disabled:cursor-not-allowed"
|
||||
)}
|
||||
placeholder="Ask me a question about Medusa..."
|
||||
@@ -319,23 +358,22 @@ export const AiAssistant = () => {
|
||||
passedRef={inputRef}
|
||||
disabled={loading}
|
||||
/>
|
||||
<Button
|
||||
variant="transparent"
|
||||
<span
|
||||
onClick={() => {
|
||||
setQuestion("")
|
||||
inputRef.current?.focus()
|
||||
}}
|
||||
className={clsx(
|
||||
"text-medusa-fg-subtle p-[5px]",
|
||||
"text-medusa-fg-muted hover:text-medusa-fg-subtle",
|
||||
"absolute top-docs_0.75 right-docs_1",
|
||||
"hover:bg-medusa-bg-base-hover rounded-docs_sm",
|
||||
"cursor-pointer",
|
||||
question.length === 0 && "hidden"
|
||||
)}
|
||||
>
|
||||
<XMarkMini />
|
||||
</Button>
|
||||
Clear
|
||||
</span>
|
||||
</div>
|
||||
<div className="h-[calc(100%-120px)] md:h-[calc(100%-114px)] lg:max-h-[calc(100%-114px)] lg:min-h-[calc(100%-114px)] overflow-auto">
|
||||
<div className="h-[calc(100%-95px)] lg:max-h-[calc(100%-140px)] lg:min-h-[calc(100%-140px)] overflow-auto">
|
||||
<div ref={contentRef}>
|
||||
{!thread.length && (
|
||||
<div className="mx-docs_0.5">
|
||||
@@ -372,35 +410,12 @@ export const AiAssistant = () => {
|
||||
</div>
|
||||
<div
|
||||
className={clsx(
|
||||
"py-docs_0.75 flex items-center justify-between px-docs_1",
|
||||
"border-0 border-solid",
|
||||
"py-docs_0.75 hidden md:flex items-center justify-end px-docs_1",
|
||||
"border-medusa-border-base border-t",
|
||||
"bg-medusa-bg-base h-[57px]"
|
||||
"bg-medusa-bg-field-component"
|
||||
)}
|
||||
>
|
||||
<Tooltip
|
||||
tooltipChildren={
|
||||
<>
|
||||
This site is protected by reCAPTCHA and the{" "}
|
||||
<Link href="https://policies.google.com/privacy">
|
||||
Google Privacy Policy
|
||||
</Link>{" "}
|
||||
and <Link href="https://policies.google.com/terms">ToS</Link>{" "}
|
||||
apply
|
||||
</>
|
||||
}
|
||||
>
|
||||
<div
|
||||
className={clsx(
|
||||
"flex items-center gap-docs_0.75 text-compact-small-plus"
|
||||
)}
|
||||
>
|
||||
<AiAssistantIcon />
|
||||
<span className="text-medusa-fg-subtle">Medusa AI Assistant</span>
|
||||
<Badge variant="purple">Beta</Badge>
|
||||
</div>
|
||||
</Tooltip>
|
||||
<div className="hidden items-center gap-docs_1 md:flex">
|
||||
<div className="flex items-center gap-docs_0.75">
|
||||
<div className="flex items-center gap-docs_0.5">
|
||||
{thread.length === 0 && (
|
||||
<>
|
||||
@@ -412,9 +427,23 @@ export const AiAssistant = () => {
|
||||
>
|
||||
Navigate FAQ
|
||||
</span>
|
||||
<span className="gap-docs_0.25 flex">
|
||||
<Kbd>↑</Kbd>
|
||||
<Kbd>↓</Kbd>
|
||||
<span className="gap-[5px] flex">
|
||||
<Kbd
|
||||
className={clsx(
|
||||
"!bg-medusa-bg-field-component !border-medusa-border-strong",
|
||||
"!text-medusa-fg-subtle h-[18px] w-[18px] p-0"
|
||||
)}
|
||||
>
|
||||
↑
|
||||
</Kbd>
|
||||
<Kbd
|
||||
className={clsx(
|
||||
"!bg-medusa-bg-field-component !border-medusa-border-strong",
|
||||
"!text-medusa-fg-subtle h-[18px] w-[18px] p-0"
|
||||
)}
|
||||
>
|
||||
↓
|
||||
</Kbd>
|
||||
</span>
|
||||
</>
|
||||
)}
|
||||
@@ -426,13 +455,23 @@ export const AiAssistant = () => {
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<div
|
||||
className={clsx("h-docs_0.75 w-px bg-medusa-border-strong")}
|
||||
></div>
|
||||
<div className="flex items-center gap-docs_0.5">
|
||||
<span
|
||||
className={clsx("text-medusa-fg-subtle", "text-compact-x-small")}
|
||||
>
|
||||
Ask Question
|
||||
</span>
|
||||
<Kbd>↵</Kbd>
|
||||
<Kbd
|
||||
className={clsx(
|
||||
"!bg-medusa-bg-field-component !border-medusa-border-strong",
|
||||
"!text-medusa-fg-subtle h-[18px] w-[18px] p-0"
|
||||
)}
|
||||
>
|
||||
↵
|
||||
</Kbd>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -11,27 +11,38 @@ export const AiAssistantIcon = (props: IconProps) => {
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}
|
||||
>
|
||||
<g filter="url(#filter0_diii_7480_20594)">
|
||||
<g filter="url(#filter0_diii_10448_46450)">
|
||||
<circle
|
||||
cx="9.5"
|
||||
cy="9.00002"
|
||||
cx="9.50002"
|
||||
cy="8.99989"
|
||||
r="7.11"
|
||||
fill="url(#paint0_linear_7480_20594)"
|
||||
fill="url(#paint0_linear_10448_46450)"
|
||||
/>
|
||||
<circle
|
||||
cx="9.5"
|
||||
cy="9.00002"
|
||||
cx="9.50002"
|
||||
cy="8.99989"
|
||||
r="7.11"
|
||||
fill="url(#paint1_linear_7480_20594)"
|
||||
fill="url(#paint1_linear_10448_46450)"
|
||||
/>
|
||||
</g>
|
||||
<g filter="url(#filter1_f_7480_20594)">
|
||||
<circle cx="9.5" cy="6.5" r="4" fill="url(#paint2_linear_7480_20594)" />
|
||||
<g
|
||||
style={{
|
||||
mixBlendMode: "plus-lighter",
|
||||
}}
|
||||
opacity="0.8"
|
||||
filter="url(#filter1_f_10448_46450)"
|
||||
>
|
||||
<circle
|
||||
cx="9.5"
|
||||
cy="6.5"
|
||||
r="4"
|
||||
fill="url(#paint2_linear_10448_46450)"
|
||||
/>
|
||||
<circle
|
||||
cx="9.5"
|
||||
cy="6.5"
|
||||
r="3.9"
|
||||
stroke="url(#paint3_linear_7480_20594)"
|
||||
stroke="url(#paint3_linear_10448_46450)"
|
||||
strokeWidth="0.2"
|
||||
/>
|
||||
</g>
|
||||
@@ -39,14 +50,15 @@ export const AiAssistantIcon = (props: IconProps) => {
|
||||
style={{
|
||||
mixBlendMode: "plus-lighter",
|
||||
}}
|
||||
filter="url(#filter2_f_7480_20594)"
|
||||
opacity="0.8"
|
||||
filter="url(#filter2_f_10448_46450)"
|
||||
>
|
||||
<circle cx="12" cy="10" r="4" fill="url(#paint4_linear_7480_20594)" />
|
||||
<circle cx="12" cy="10" r="4" fill="url(#paint4_linear_10448_46450)" />
|
||||
<circle
|
||||
cx="12"
|
||||
cy="10"
|
||||
r="3.9"
|
||||
stroke="url(#paint5_linear_7480_20594)"
|
||||
stroke="url(#paint5_linear_10448_46450)"
|
||||
strokeWidth="0.2"
|
||||
/>
|
||||
</g>
|
||||
@@ -54,21 +66,22 @@ export const AiAssistantIcon = (props: IconProps) => {
|
||||
style={{
|
||||
mixBlendMode: "plus-lighter",
|
||||
}}
|
||||
filter="url(#filter3_f_7480_20594)"
|
||||
opacity="0.8"
|
||||
filter="url(#filter3_f_10448_46450)"
|
||||
>
|
||||
<circle
|
||||
cx="4"
|
||||
cy="4"
|
||||
r="4"
|
||||
transform="matrix(-1 0 0 1 11 4)"
|
||||
fill="url(#paint6_linear_7480_20594)"
|
||||
fill="url(#paint6_linear_10448_46450)"
|
||||
/>
|
||||
<circle
|
||||
cx="4"
|
||||
cy="4"
|
||||
r="3.9"
|
||||
transform="matrix(-1 0 0 1 11 4)"
|
||||
stroke="url(#paint7_linear_7480_20594)"
|
||||
stroke="url(#paint7_linear_10448_46450)"
|
||||
strokeWidth="0.2"
|
||||
/>
|
||||
</g>
|
||||
@@ -76,46 +89,53 @@ export const AiAssistantIcon = (props: IconProps) => {
|
||||
style={{
|
||||
mixBlendMode: "plus-lighter",
|
||||
}}
|
||||
filter="url(#filter4_f_7480_20594)"
|
||||
opacity="0.8"
|
||||
filter="url(#filter4_f_10448_46450)"
|
||||
>
|
||||
<circle
|
||||
cx="4"
|
||||
cy="4"
|
||||
r="4"
|
||||
transform="matrix(0 -1 -1 0 13.5 13)"
|
||||
fill="url(#paint8_linear_7480_20594)"
|
||||
fill="url(#paint8_linear_10448_46450)"
|
||||
/>
|
||||
<circle
|
||||
cx="4"
|
||||
cy="4"
|
||||
r="3.9"
|
||||
transform="matrix(0 -1 -1 0 13.5 13)"
|
||||
stroke="url(#paint9_linear_7480_20594)"
|
||||
stroke="url(#paint9_linear_10448_46450)"
|
||||
strokeWidth="0.2"
|
||||
/>
|
||||
</g>
|
||||
<g filter="url(#filter5_f_7480_20594)">
|
||||
<g
|
||||
style={{
|
||||
mixBlendMode: "plus-lighter",
|
||||
}}
|
||||
opacity="0.8"
|
||||
filter="url(#filter5_f_10448_46450)"
|
||||
>
|
||||
<circle
|
||||
cx="4"
|
||||
cy="4"
|
||||
r="4"
|
||||
transform="matrix(-1 0 0 1 13.5 7.5)"
|
||||
fill="url(#paint10_linear_7480_20594)"
|
||||
fill="url(#paint10_linear_10448_46450)"
|
||||
/>
|
||||
<circle
|
||||
cx="4"
|
||||
cy="4"
|
||||
r="3.9"
|
||||
transform="matrix(-1 0 0 1 13.5 7.5)"
|
||||
stroke="url(#paint11_linear_7480_20594)"
|
||||
stroke="url(#paint11_linear_10448_46450)"
|
||||
strokeWidth="0.2"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<filter
|
||||
id="filter0_diii_7480_20594"
|
||||
x="0.389999"
|
||||
y="0.890015"
|
||||
id="filter0_diii_10448_46450"
|
||||
x="0.390015"
|
||||
y="0.889893"
|
||||
width="18.22"
|
||||
height="18.22"
|
||||
filterUnits="userSpaceOnUse"
|
||||
@@ -138,12 +158,12 @@ export const AiAssistantIcon = (props: IconProps) => {
|
||||
<feBlend
|
||||
mode="normal"
|
||||
in2="BackgroundImageFix"
|
||||
result="effect1_dropShadow_7480_20594"
|
||||
result="effect1_dropShadow_10448_46450"
|
||||
/>
|
||||
<feBlend
|
||||
mode="normal"
|
||||
in="SourceGraphic"
|
||||
in2="effect1_dropShadow_7480_20594"
|
||||
in2="effect1_dropShadow_10448_46450"
|
||||
result="shape"
|
||||
/>
|
||||
<feColorMatrix
|
||||
@@ -161,7 +181,7 @@ export const AiAssistantIcon = (props: IconProps) => {
|
||||
<feBlend
|
||||
mode="normal"
|
||||
in2="shape"
|
||||
result="effect2_innerShadow_7480_20594"
|
||||
result="effect2_innerShadow_10448_46450"
|
||||
/>
|
||||
<feColorMatrix
|
||||
in="SourceAlpha"
|
||||
@@ -173,12 +193,12 @@ export const AiAssistantIcon = (props: IconProps) => {
|
||||
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1" />
|
||||
<feColorMatrix
|
||||
type="matrix"
|
||||
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0"
|
||||
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.4 0"
|
||||
/>
|
||||
<feBlend
|
||||
mode="normal"
|
||||
in2="effect2_innerShadow_7480_20594"
|
||||
result="effect3_innerShadow_7480_20594"
|
||||
in2="effect2_innerShadow_10448_46450"
|
||||
result="effect3_innerShadow_10448_46450"
|
||||
/>
|
||||
<feColorMatrix
|
||||
in="SourceAlpha"
|
||||
@@ -195,12 +215,12 @@ export const AiAssistantIcon = (props: IconProps) => {
|
||||
/>
|
||||
<feBlend
|
||||
mode="normal"
|
||||
in2="effect3_innerShadow_7480_20594"
|
||||
result="effect4_innerShadow_7480_20594"
|
||||
in2="effect3_innerShadow_10448_46450"
|
||||
result="effect4_innerShadow_10448_46450"
|
||||
/>
|
||||
</filter>
|
||||
<filter
|
||||
id="filter1_f_7480_20594"
|
||||
id="filter1_f_10448_46450"
|
||||
x="5"
|
||||
y="2"
|
||||
width="9"
|
||||
@@ -217,11 +237,11 @@ export const AiAssistantIcon = (props: IconProps) => {
|
||||
/>
|
||||
<feGaussianBlur
|
||||
stdDeviation="0.25"
|
||||
result="effect1_foregroundBlur_7480_20594"
|
||||
result="effect1_foregroundBlur_10448_46450"
|
||||
/>
|
||||
</filter>
|
||||
<filter
|
||||
id="filter2_f_7480_20594"
|
||||
id="filter2_f_10448_46450"
|
||||
x="7.5"
|
||||
y="5.5"
|
||||
width="9"
|
||||
@@ -238,11 +258,11 @@ export const AiAssistantIcon = (props: IconProps) => {
|
||||
/>
|
||||
<feGaussianBlur
|
||||
stdDeviation="0.25"
|
||||
result="effect1_foregroundBlur_7480_20594"
|
||||
result="effect1_foregroundBlur_10448_46450"
|
||||
/>
|
||||
</filter>
|
||||
<filter
|
||||
id="filter3_f_7480_20594"
|
||||
id="filter3_f_10448_46450"
|
||||
x="2.5"
|
||||
y="3.5"
|
||||
width="9"
|
||||
@@ -259,11 +279,11 @@ export const AiAssistantIcon = (props: IconProps) => {
|
||||
/>
|
||||
<feGaussianBlur
|
||||
stdDeviation="0.25"
|
||||
result="effect1_foregroundBlur_7480_20594"
|
||||
result="effect1_foregroundBlur_10448_46450"
|
||||
/>
|
||||
</filter>
|
||||
<filter
|
||||
id="filter4_f_7480_20594"
|
||||
id="filter4_f_10448_46450"
|
||||
x="5"
|
||||
y="4.5"
|
||||
width="9"
|
||||
@@ -280,11 +300,11 @@ export const AiAssistantIcon = (props: IconProps) => {
|
||||
/>
|
||||
<feGaussianBlur
|
||||
stdDeviation="0.25"
|
||||
result="effect1_foregroundBlur_7480_20594"
|
||||
result="effect1_foregroundBlur_10448_46450"
|
||||
/>
|
||||
</filter>
|
||||
<filter
|
||||
id="filter5_f_7480_20594"
|
||||
id="filter5_f_10448_46450"
|
||||
x="5"
|
||||
y="7"
|
||||
width="9"
|
||||
@@ -301,44 +321,44 @@ export const AiAssistantIcon = (props: IconProps) => {
|
||||
/>
|
||||
<feGaussianBlur
|
||||
stdDeviation="0.25"
|
||||
result="effect1_foregroundBlur_7480_20594"
|
||||
result="effect1_foregroundBlur_10448_46450"
|
||||
/>
|
||||
</filter>
|
||||
<linearGradient
|
||||
id="paint0_linear_7480_20594"
|
||||
x1="9.5"
|
||||
y1="1.89002"
|
||||
x2="9.5"
|
||||
y2="16.11"
|
||||
id="paint0_linear_10448_46450"
|
||||
x1="9.50001"
|
||||
y1="1.88989"
|
||||
x2="9.50001"
|
||||
y2="16.1099"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop offset="0.2" stopColor="#8952FD" />
|
||||
<stop offset="0.8" stopColor="#48EAEB" />
|
||||
<stop offset="0.2" stopColor="#C686FF" />
|
||||
<stop offset="0.8" stopColor="#8D99FF" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint1_linear_7480_20594"
|
||||
x1="5.11519"
|
||||
y1="8.96784"
|
||||
id="paint1_linear_10448_46450"
|
||||
x1="5.1152"
|
||||
y1="8.96772"
|
||||
x2="13.4627"
|
||||
y2="12.0584"
|
||||
y2="12.0583"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stopColor="#5B53FF" stopOpacity="0.8" />
|
||||
<stop stopColor="#FF6778" stopOpacity="0.8" />
|
||||
<stop offset="1" stopColor="white" stopOpacity="0.1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint2_linear_7480_20594"
|
||||
id="paint2_linear_10448_46450"
|
||||
x1="9.5"
|
||||
y1="6.5"
|
||||
x2="13.5"
|
||||
y2="6.5"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stopColor="#5B53FF" stopOpacity="0.1" />
|
||||
<stop stopColor="#8D99FF" stopOpacity="0.1" />
|
||||
<stop offset="1" stopColor="white" stopOpacity="0.3" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint3_linear_7480_20594"
|
||||
id="paint3_linear_10448_46450"
|
||||
x1="13.5"
|
||||
y1="6.5"
|
||||
x2="9.5"
|
||||
@@ -349,84 +369,84 @@ export const AiAssistantIcon = (props: IconProps) => {
|
||||
<stop offset="1" stopColor="white" stopOpacity="0" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint4_linear_7480_20594"
|
||||
id="paint4_linear_10448_46450"
|
||||
x1="12"
|
||||
y1="10"
|
||||
x2="16"
|
||||
y2="10"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stopColor="#5B53FF" stopOpacity="0.1" />
|
||||
<stop stopColor="#8D99FF" stopOpacity="0.1" />
|
||||
<stop offset="1" stopColor="white" stopOpacity="0.3" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint5_linear_7480_20594"
|
||||
id="paint5_linear_10448_46450"
|
||||
x1="16"
|
||||
y1="10"
|
||||
x2="12"
|
||||
y2="10"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stopColor="#3B82F6" />
|
||||
<stop offset="1" stopColor="#3B82F6" stopOpacity="0" />
|
||||
<stop stopColor="#8D99FF" />
|
||||
<stop offset="1" stopColor="#8D99FF" stopOpacity="0" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint6_linear_7480_20594"
|
||||
id="paint6_linear_10448_46450"
|
||||
x1="4"
|
||||
y1="4"
|
||||
x2="8"
|
||||
y2="4"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stopColor="#5B53FF" stopOpacity="0.1" />
|
||||
<stop stopColor="#8D99FF" stopOpacity="0.1" />
|
||||
<stop offset="1" stopColor="white" stopOpacity="0.3" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint7_linear_7480_20594"
|
||||
id="paint7_linear_10448_46450"
|
||||
x1="8"
|
||||
y1="4"
|
||||
x2="4"
|
||||
y2="4"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stopColor="#48EAEB" />
|
||||
<stop offset="1" stopColor="#48EAEB" stopOpacity="0" />
|
||||
<stop stopColor="#8D99FF" />
|
||||
<stop offset="1" stopColor="#8D99FF" stopOpacity="0" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint8_linear_7480_20594"
|
||||
id="paint8_linear_10448_46450"
|
||||
x1="4"
|
||||
y1="4"
|
||||
x2="8"
|
||||
y2="4"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stopColor="#5B53FF" stopOpacity="0.1" />
|
||||
<stop stopColor="#8D99FF" stopOpacity="0.1" />
|
||||
<stop offset="1" stopColor="white" stopOpacity="0.3" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint9_linear_7480_20594"
|
||||
id="paint9_linear_10448_46450"
|
||||
x1="8"
|
||||
y1="4"
|
||||
x2="4"
|
||||
y2="4"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stopColor="#3B82F6" />
|
||||
<stop offset="1" stopColor="#3B82F6" stopOpacity="0" />
|
||||
<stop stopColor="#8D99FF" />
|
||||
<stop offset="1" stopColor="#8D99FF" stopOpacity="0" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint10_linear_7480_20594"
|
||||
id="paint10_linear_10448_46450"
|
||||
x1="4"
|
||||
y1="4"
|
||||
x2="8"
|
||||
y2="4"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
>
|
||||
<stop stopColor="#5B53FF" stopOpacity="0.1" />
|
||||
<stop stopColor="#8D99FF" stopOpacity="0.1" />
|
||||
<stop offset="1" stopColor="white" stopOpacity="0.3" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="paint11_linear_7480_20594"
|
||||
id="paint11_linear_10448_46450"
|
||||
x1="8"
|
||||
y1="4"
|
||||
x2="4"
|
||||
|
||||
@@ -16,17 +16,17 @@ export const ShadedBgIcon = ({
|
||||
switch (variant) {
|
||||
case "neutral":
|
||||
case "code":
|
||||
return "#E4E4E7"
|
||||
return "var(--docs-tags-neutral-border)"
|
||||
case "blue":
|
||||
return "#BFDBFE"
|
||||
return "var(--docs-tags-blue-border)"
|
||||
case "purple":
|
||||
return "#DDD6FE"
|
||||
return "var(--docs-tags-purple-border)"
|
||||
case "green":
|
||||
return "#A7F3D0"
|
||||
return "var(--docs-tags-green-border)"
|
||||
case "orange":
|
||||
return "#FED7AA"
|
||||
return "var(--docs-tags-orange-border)"
|
||||
case "red":
|
||||
return "#FECDD3"
|
||||
return "var(--docs-tags-red-border)"
|
||||
}
|
||||
}, [variant])
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@ export const Modal = ({
|
||||
className={clsx(
|
||||
"fixed top-0 left-0 flex h-screen w-screen items-center justify-center",
|
||||
"bg-medusa-bg-overlay z-50",
|
||||
"hidden open:flex border-0 p-0",
|
||||
"hidden open:flex border-0 px-docs_0.5 lg:p-0",
|
||||
className
|
||||
)}
|
||||
onClick={handleClick}
|
||||
@@ -99,17 +99,17 @@ export const Modal = ({
|
||||
>
|
||||
<div
|
||||
className={clsx(
|
||||
"bg-medusa-bg-base rounded-docs_sm",
|
||||
"border-medusa-border-base border border-solid",
|
||||
"bg-medusa-bg-base rounded-docs_lg",
|
||||
"shadow-elevation-modal dark:shadow-elevation-modal-dark",
|
||||
"w-[90%] md:h-auto md:w-[75%] lg:w-[560px]",
|
||||
"max-w-full sm:max-w-modal-sm md:max-w-modal-md lg:max-w-modal-lg",
|
||||
"h-auto w-full",
|
||||
modalContainerClassName
|
||||
)}
|
||||
>
|
||||
{title && <ModalHeader title={title} />}
|
||||
<div
|
||||
className={clsx(
|
||||
"overflow-auto py-docs_1.5 px-docs_2",
|
||||
"overflow-auto py-docs_1.5 px-docs_2 rounded-docs_lg",
|
||||
contentClassName
|
||||
)}
|
||||
>
|
||||
|
||||
59
www/packages/docs-ui/src/components/Search/Footer/index.tsx
Normal file
59
www/packages/docs-ui/src/components/Search/Footer/index.tsx
Normal file
@@ -0,0 +1,59 @@
|
||||
import clsx from "clsx"
|
||||
import React from "react"
|
||||
import { Kbd } from "../../.."
|
||||
|
||||
export const SearchFooter = () => {
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
"py-docs_0.75 hidden md:flex items-center justify-end px-docs_1",
|
||||
"border-medusa-border-base border-t",
|
||||
"bg-medusa-bg-field"
|
||||
)}
|
||||
>
|
||||
<div className="flex items-center gap-docs_0.75">
|
||||
<div className="flex items-center gap-docs_0.5">
|
||||
<span
|
||||
className={clsx("text-medusa-fg-subtle", "text-compact-x-small")}
|
||||
>
|
||||
Navigation
|
||||
</span>
|
||||
<span className="gap-[5px] flex">
|
||||
<Kbd
|
||||
className={clsx(
|
||||
"!bg-medusa-bg-field-component !border-medusa-border-strong",
|
||||
"!text-medusa-fg-subtle h-[18px] w-[18px] p-0"
|
||||
)}
|
||||
>
|
||||
↑
|
||||
</Kbd>
|
||||
<Kbd
|
||||
className={clsx(
|
||||
"!bg-medusa-bg-field-component !border-medusa-border-strong",
|
||||
"!text-medusa-fg-subtle h-[18px] w-[18px] p-0"
|
||||
)}
|
||||
>
|
||||
↓
|
||||
</Kbd>
|
||||
</span>
|
||||
</div>
|
||||
<div className={clsx("h-docs_0.75 w-px bg-medusa-border-strong")}></div>
|
||||
<div className="flex items-center gap-docs_0.5">
|
||||
<span
|
||||
className={clsx("text-medusa-fg-subtle", "text-compact-x-small")}
|
||||
>
|
||||
Open Result
|
||||
</span>
|
||||
<Kbd
|
||||
className={clsx(
|
||||
"!bg-medusa-bg-field-component !border-medusa-border-strong",
|
||||
"!text-medusa-fg-subtle h-[18px] w-[18px] p-0"
|
||||
)}
|
||||
>
|
||||
↵
|
||||
</Kbd>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -9,7 +9,7 @@ export const SearchHitGroupName = ({ name }: SearchHitGroupNameProps) => {
|
||||
return (
|
||||
<span
|
||||
className={clsx(
|
||||
"pb-docs_0.25 flex px-docs_0.5 pt-docs_1",
|
||||
"pb-docs_0.25 flex px-docs_0.5 pt-docs_0.75",
|
||||
"text-medusa-fg-muted",
|
||||
"text-compact-x-small-plus"
|
||||
)}
|
||||
|
||||
@@ -70,7 +70,7 @@ export const SearchHitsWrapper = ({
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="h-full overflow-auto">
|
||||
<div className="h-full overflow-auto px-docs_0.5">
|
||||
{status !== "loading" && showNoResults && <SearchNoResult />}
|
||||
{indices.map((indexName, index) => (
|
||||
<Index indexName={indexName} key={index}>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ExclamationCircleSolid } from "@medusajs/icons"
|
||||
import { MagnifierAlert } from "@medusajs/icons"
|
||||
import clsx from "clsx"
|
||||
import React from "react"
|
||||
|
||||
@@ -6,14 +6,24 @@ export const SearchNoResult = () => {
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
"flex h-full w-full flex-col items-center justify-center gap-docs_1",
|
||||
"text-medusa-fg-muted"
|
||||
"flex h-full w-full flex-col items-center justify-center gap-docs_0.75"
|
||||
)}
|
||||
>
|
||||
<ExclamationCircleSolid />
|
||||
<span className="text-compact-small">
|
||||
No results found. Try changing selected filters.
|
||||
</span>
|
||||
<MagnifierAlert className="text-medusa-fg-base" />
|
||||
<div
|
||||
className={clsx(
|
||||
"flex flex-col justify-center items-center gap-docs_0.25",
|
||||
"max-w-[360px]"
|
||||
)}
|
||||
>
|
||||
<span className="text-compact-small-plus text-medusa-fg-subtle">
|
||||
No results found.
|
||||
</span>
|
||||
<span className="text-medusa-fg-muted txt-small text-center">
|
||||
We couldn't find any matches for your search. Please try changing
|
||||
the filters or using different keywords.
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ export const SearchSuggestionItem = ({
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
"flex items-center",
|
||||
"flex items-center justify-between gap-docs_0.75",
|
||||
"cursor-pointer rounded-docs_sm p-docs_0.5",
|
||||
"hover:bg-medusa-bg-base-hover",
|
||||
"focus:bg-medusa-bg-base-hover",
|
||||
|
||||
@@ -21,7 +21,7 @@ export const SearchSuggestions = ({ suggestions }: SearchSuggestionsProps) => {
|
||||
const { commands, setCommand } = useSearch()
|
||||
|
||||
return (
|
||||
<div className="h-full overflow-auto">
|
||||
<div className="h-full overflow-auto px-docs_0.5">
|
||||
{commands.length > 0 && (
|
||||
<>
|
||||
<SearchHitGroupName name={"Commands"} />
|
||||
@@ -30,12 +30,9 @@ export const SearchSuggestions = ({ suggestions }: SearchSuggestionsProps) => {
|
||||
onClick={() => setCommand(command)}
|
||||
key={index}
|
||||
tabIndex={index}
|
||||
className="justify-between"
|
||||
>
|
||||
<span className="flex gap-docs_0.75">
|
||||
{command.icon}
|
||||
<span>{command.title}</span>
|
||||
</span>
|
||||
{command.icon}
|
||||
<span className="flex-1">{command.title}</span>
|
||||
{command.badge && <Badge {...command.badge} />}
|
||||
</SearchSuggestionItem>
|
||||
))}
|
||||
|
||||
@@ -8,9 +8,10 @@ import { SearchSuggestions, type SearchSuggestionType } from "./Suggestions"
|
||||
import { AlgoliaProps, useSearch } from "@/providers"
|
||||
import { checkArraySameElms } from "@/utils"
|
||||
import { SearchHitsWrapper } from "./Hits"
|
||||
import { Button, Kbd, SelectBadge } from "@/components"
|
||||
import { Button, Kbd, SelectBadge, SpinnerLoading } from "@/components"
|
||||
import { MagnifyingGlass, XMark } from "@medusajs/icons"
|
||||
import { useSearchNavigation, type OptionType } from "@/hooks"
|
||||
import { SearchFooter } from "./Footer"
|
||||
|
||||
export type SearchProps = {
|
||||
algolia: AlgoliaProps
|
||||
@@ -68,7 +69,31 @@ export const Search = ({
|
||||
})
|
||||
|
||||
return (
|
||||
<div className="h-full">
|
||||
<div className="h-full flex flex-col">
|
||||
{filterOptions.length && (
|
||||
<SelectBadge
|
||||
multiple
|
||||
options={filterOptions}
|
||||
value={filters}
|
||||
setSelected={(value) =>
|
||||
setFilters(Array.isArray(value) ? [...value] : [value])
|
||||
}
|
||||
addSelected={(value) => setFilters((prev) => [...prev, value])}
|
||||
removeSelected={(value) =>
|
||||
setFilters((prev) => prev.filter((v) => v !== value))
|
||||
}
|
||||
showClearButton={false}
|
||||
placeholder="Filters"
|
||||
handleAddAll={(isAllSelected: boolean) => {
|
||||
if (isAllSelected) {
|
||||
setFilters(defaultFilters)
|
||||
} else {
|
||||
setFilters(filterOptions.map((option) => option.value))
|
||||
}
|
||||
}}
|
||||
className="px-docs_1 pt-docs_1 bg-medusa-bg-base"
|
||||
/>
|
||||
)}
|
||||
<InstantSearch
|
||||
indexName={algolia.mainIndexName}
|
||||
searchClient={searchClient}
|
||||
@@ -86,27 +111,25 @@ export const Search = ({
|
||||
),
|
||||
form: clsx("h-full md:rounded-t-docs_xl bg-transparent"),
|
||||
input: clsx(
|
||||
"w-full h-full pl-docs_3 text-medusa-fg-base",
|
||||
"placeholder:text-medusa-fg-muted",
|
||||
"md:rounded-t-docs_xl text-compact-medium bg-transparent",
|
||||
"w-full h-full px-docs_1 py-docs_0.75 text-medusa-fg-base",
|
||||
"placeholder:text-medusa-fg-muted bg-medusa-bg-base",
|
||||
"md:rounded-t-docs_xl text-compact-medium",
|
||||
"appearance-none search-cancel:hidden border-0 active:outline-none focus:outline-none"
|
||||
),
|
||||
submit: clsx("absolute top-[18px] left-docs_1 btn-clear p-0"),
|
||||
reset: clsx(
|
||||
"absolute top-docs_0.75 right-docs_1 hover:bg-medusa-bg-base-hover",
|
||||
"p-[5px] md:rounded-docs_DEFAULT btn-clear"
|
||||
),
|
||||
reset: clsx("absolute top-[18px] right-docs_1", "btn-clear"),
|
||||
loadingIndicator: clsx("absolute top-[18px] right-docs_1"),
|
||||
}}
|
||||
submitIconComponent={() => (
|
||||
<MagnifyingGlass className="text-medusa-fg-muted" />
|
||||
)}
|
||||
submitIconComponent={() => <></>}
|
||||
resetIconComponent={() => (
|
||||
<XMark className="hidden md:block text-medusa-fg-subtle" />
|
||||
<span className="text-medusa-fg-muted text-compact-small-plus hover:text-medusa-fg-subtle">
|
||||
Clear
|
||||
</span>
|
||||
)}
|
||||
placeholder="Find something..."
|
||||
autoFocus
|
||||
formRef={searchBoxRef}
|
||||
loadingIconComponent={() => <SpinnerLoading />}
|
||||
/>
|
||||
<Button
|
||||
variant="transparent"
|
||||
@@ -121,7 +144,7 @@ export const Search = ({
|
||||
<XMark className="text-medusa-fg-muted" />
|
||||
</Button>
|
||||
</div>
|
||||
<div className="mx-docs_0.5 md:flex-initial h-[calc(100%-120px)] md:h-[calc(100%-114px)] lg:max-h-[calc(100%-114px)] lg:min-h-[calc(100%-114px)]">
|
||||
<div className="md:flex-initial h-[calc(100%-95px)] lg:max-h-[calc(100%-140px)] lg:min-h-[calc(100%-140px)]">
|
||||
<SearchEmptyQueryBoundary
|
||||
fallback={<SearchSuggestions suggestions={suggestions} />}
|
||||
>
|
||||
@@ -135,59 +158,7 @@ export const Search = ({
|
||||
</SearchEmptyQueryBoundary>
|
||||
</div>
|
||||
</InstantSearch>
|
||||
<div
|
||||
className={clsx(
|
||||
"py-docs_0.75 flex items-center justify-between px-docs_1",
|
||||
"border-0 border-solid h-[57px]",
|
||||
"border-medusa-border-base border-t",
|
||||
"bg-medusa-bg-base"
|
||||
)}
|
||||
>
|
||||
{filterOptions.length && (
|
||||
<SelectBadge
|
||||
multiple
|
||||
options={filterOptions}
|
||||
value={filters}
|
||||
setSelected={(value) =>
|
||||
setFilters(Array.isArray(value) ? [...value] : [value])
|
||||
}
|
||||
addSelected={(value) => setFilters((prev) => [...prev, value])}
|
||||
removeSelected={(value) =>
|
||||
setFilters((prev) => prev.filter((v) => v !== value))
|
||||
}
|
||||
showClearButton={false}
|
||||
placeholder="Filters"
|
||||
handleAddAll={(isAllSelected: boolean) => {
|
||||
if (isAllSelected) {
|
||||
setFilters(defaultFilters)
|
||||
} else {
|
||||
setFilters(filterOptions.map((option) => option.value))
|
||||
}
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<div className="hidden items-center gap-docs_1 md:flex">
|
||||
<div className="flex items-center gap-docs_0.5">
|
||||
<span
|
||||
className={clsx("text-medusa-fg-subtle", "text-compact-x-small")}
|
||||
>
|
||||
Navigation
|
||||
</span>
|
||||
<span className="gap-docs_0.25 flex">
|
||||
<Kbd>↑</Kbd>
|
||||
<Kbd>↓</Kbd>
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-docs_0.5">
|
||||
<span
|
||||
className={clsx("text-medusa-fg-subtle", "text-compact-x-small")}
|
||||
>
|
||||
Open Result
|
||||
</span>
|
||||
<Kbd>↵</Kbd>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<SearchFooter />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import React, { useCallback, useRef, useState } from "react"
|
||||
import { useSelect } from "@/hooks"
|
||||
import clsx from "clsx"
|
||||
import { SelectDropdown, SelectProps } from ".."
|
||||
import { TriangleDownMini } from "@medusajs/icons"
|
||||
|
||||
export const SelectBadge = ({
|
||||
value,
|
||||
@@ -20,16 +21,21 @@ export const SelectBadge = ({
|
||||
const [open, setOpen] = useState(false)
|
||||
const ref = useRef<HTMLDivElement>(null)
|
||||
const dropdownRef = useRef<HTMLDivElement>(null)
|
||||
const { isValueSelected, isAllSelected, handleChange, handleSelectAll } =
|
||||
useSelect({
|
||||
value,
|
||||
options,
|
||||
multiple,
|
||||
setSelected,
|
||||
removeSelected,
|
||||
addSelected,
|
||||
handleAddAll,
|
||||
})
|
||||
const {
|
||||
isValueSelected,
|
||||
isAllSelected,
|
||||
handleChange,
|
||||
handleSelectAll,
|
||||
setSelectedValues,
|
||||
} = useSelect({
|
||||
value,
|
||||
options,
|
||||
multiple,
|
||||
setSelected,
|
||||
removeSelected,
|
||||
addSelected,
|
||||
handleAddAll,
|
||||
})
|
||||
|
||||
const getSelectedText = useCallback(() => {
|
||||
let str = ""
|
||||
@@ -38,7 +44,7 @@ export const SelectBadge = ({
|
||||
)
|
||||
|
||||
if (isAllSelected) {
|
||||
str = "All Areas"
|
||||
str = "All areas"
|
||||
} else {
|
||||
if (
|
||||
(!Array.isArray(value) && !value) ||
|
||||
@@ -54,37 +60,28 @@ export const SelectBadge = ({
|
||||
<>
|
||||
<span
|
||||
className={clsx(
|
||||
"text-medusa-fg-base",
|
||||
"text-compact-x-small-plus",
|
||||
"inline-block max-w-[60px] overflow-hidden text-ellipsis"
|
||||
"text-compact-x-small-plus text-medusa-tag-neutral-text"
|
||||
)}
|
||||
>
|
||||
{str}
|
||||
{!isAllSelected && selectedOptions.length > 1 && (
|
||||
<> + {selectedOptions.length - 1}</>
|
||||
)}
|
||||
</span>
|
||||
{!isAllSelected && selectedOptions.length > 1 && (
|
||||
<span
|
||||
className={clsx("text-medusa-fg-subtle", "text-compact-x-small")}
|
||||
>
|
||||
{" "}
|
||||
+ {selectedOptions.length}
|
||||
</span>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}, [isAllSelected, options, value])
|
||||
|
||||
return (
|
||||
<div className={clsx("relative", className)}>
|
||||
<div className={clsx("relative w-fit", className)}>
|
||||
<div
|
||||
className={clsx(
|
||||
"border-medusa-border-base rounded-docs_sm border border-solid",
|
||||
"hover:bg-medusa-bg-subtle-hover",
|
||||
"py-docs_0.25 h-fit cursor-pointer px-docs_0.5",
|
||||
"flex items-center gap-[6px] whitespace-nowrap",
|
||||
"border-medusa-tag-neutral-border rounded-docs_sm border border-solid",
|
||||
"h-fit cursor-pointer pl-docs_0.25 pr-[3px] text-medusa-tag-neutral-text",
|
||||
"bg-medusa-tag-neutral-bg",
|
||||
"flex items-center gap-[3px] whitespace-nowrap",
|
||||
"text-medusa-fg-subtle",
|
||||
!open && "bg-medusa-bg-subtle",
|
||||
open && "bg-medusa-bg-subtle-hover",
|
||||
className
|
||||
open && "bg-medusa-tag-neutral-bg-hover"
|
||||
)}
|
||||
ref={ref}
|
||||
onClick={(e) => {
|
||||
@@ -93,10 +90,8 @@ export const SelectBadge = ({
|
||||
}
|
||||
}}
|
||||
>
|
||||
<span className={clsx("text-medusa-fg-subtle", "text-compact-x-small")}>
|
||||
Show results from:{" "}
|
||||
</span>
|
||||
{getSelectedText()}
|
||||
<TriangleDownMini className="text-medusa-tag-neutral-icon" />
|
||||
</div>
|
||||
<input
|
||||
type="hidden"
|
||||
@@ -115,10 +110,7 @@ export const SelectBadge = ({
|
||||
handleChange={handleChange}
|
||||
parentRef={ref}
|
||||
passedRef={dropdownRef}
|
||||
className={clsx(
|
||||
"!top-[unset] !bottom-full",
|
||||
open && "!-translate-y-docs_0.5"
|
||||
)}
|
||||
setSelectedValues={setSelectedValues}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -19,6 +19,7 @@ export type SelectDropdownProps = {
|
||||
parentRef?: React.RefObject<HTMLDivElement>
|
||||
className?: string
|
||||
passedRef?: Ref<HTMLDivElement>
|
||||
setSelectedValues?: (values: string[]) => void
|
||||
}
|
||||
|
||||
export const SelectDropdown = ({
|
||||
@@ -34,6 +35,7 @@ export const SelectDropdown = ({
|
||||
parentRef,
|
||||
className,
|
||||
passedRef,
|
||||
setSelectedValues,
|
||||
}: SelectDropdownProps) => {
|
||||
const ref = useRef<HTMLDivElement | null>(null)
|
||||
const setRefs = useCallback(
|
||||
@@ -50,7 +52,11 @@ export const SelectDropdown = ({
|
||||
)
|
||||
|
||||
const handleChange = (clickedValue: string, wasSelected: boolean) => {
|
||||
handleSelectChange?.(clickedValue, wasSelected)
|
||||
if (isAllSelected && setSelectedValues) {
|
||||
setSelectedValues([clickedValue])
|
||||
} else {
|
||||
handleSelectChange?.(clickedValue, wasSelected)
|
||||
}
|
||||
if (!multiple) {
|
||||
setOpen(false)
|
||||
}
|
||||
@@ -78,43 +84,75 @@ export const SelectDropdown = ({
|
||||
}, [handleOutsideClick])
|
||||
|
||||
const getSelectOption = (option: OptionType, index: number) => {
|
||||
const isSelected = option.isAllOption
|
||||
? isAllSelected
|
||||
: isValueSelected(option.value)
|
||||
const originalIsSelected = isValueSelected(option.value)
|
||||
const isSelected = isAllSelected
|
||||
? option.isAllOption || false
|
||||
: originalIsSelected
|
||||
|
||||
return (
|
||||
<li
|
||||
key={index}
|
||||
className={clsx(
|
||||
"pr-docs_0.75 relative rounded-docs_sm py-docs_0.5 pl-docs_2.5",
|
||||
"hover:bg-medusa-bg-base-hover",
|
||||
"[&>svg]:left-docs_0.75 cursor-pointer [&>svg]:absolute [&>svg]:top-docs_0.5",
|
||||
!isSelected && "text-compact-small",
|
||||
isSelected && "text-compact-small-plus"
|
||||
"px-docs_0.25",
|
||||
index <= 0 && "rounded-t-docs_DEFAULT",
|
||||
index === options.length - 1 && "rounded-b-docs_DEFAULT"
|
||||
)}
|
||||
onClick={() => {
|
||||
if (option.isAllOption) {
|
||||
handleSelectAll()
|
||||
} else {
|
||||
handleChange(option.value, isSelected)
|
||||
handleChange(option.value, originalIsSelected)
|
||||
}
|
||||
}}
|
||||
>
|
||||
{isSelected && (
|
||||
<>
|
||||
{multiple && <CheckMini className="text-medusa-fg-base" />}
|
||||
{!multiple && <EllipseMiniSolid className="text-medusa-fg-base" />}
|
||||
</>
|
||||
)}
|
||||
{option.label}
|
||||
<div
|
||||
className={clsx(
|
||||
"px-docs_0.5 py-docs_0.25 flex-1 min-w-max rounded-docs_xs",
|
||||
"hover:bg-medusa-bg-component-hover cursor-pointer",
|
||||
"flex gap-docs_0.5 text-medusa-fg-base items-center",
|
||||
!isSelected && "text-compact-small",
|
||||
isSelected && "text-compact-small-plus"
|
||||
)}
|
||||
>
|
||||
<span>
|
||||
{isSelected && (
|
||||
<>
|
||||
{option.isAllOption && <EllipseMiniSolid />}
|
||||
{!option.isAllOption && (
|
||||
<>
|
||||
{multiple && <CheckMini />}
|
||||
{!multiple && <EllipseMiniSolid />}
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{!isSelected && <EllipseMiniSolid className="invisible" />}
|
||||
</span>
|
||||
<span className="flex-1">{option.label}</span>
|
||||
</div>
|
||||
</li>
|
||||
)
|
||||
}
|
||||
|
||||
const getDivider = () => (
|
||||
<svg
|
||||
width="176"
|
||||
height="8"
|
||||
viewBox="0 0 176 8"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<rect width="168" height="8" transform="translate(4)" fill="#FAFAFA" />
|
||||
<rect y="4" width="176" height="1" fill="white" />
|
||||
<rect y="3" width="176" height="1" fill="#E4E4E7" />
|
||||
</svg>
|
||||
)
|
||||
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
"absolute top-full left-0 w-full",
|
||||
"absolute left-0 md:left-docs_1",
|
||||
"z-10",
|
||||
"h-0 translate-y-0 overflow-hidden transition-transform",
|
||||
open && "h-auto translate-y-docs_0.5 !overflow-visible",
|
||||
className
|
||||
@@ -123,20 +161,25 @@ export const SelectDropdown = ({
|
||||
>
|
||||
<ul
|
||||
className={clsx(
|
||||
"p-docs_0.25 mb-0 w-full overflow-auto rounded-docs_DEFAULT",
|
||||
"bg-medusa-bg-base text-medusa-fg-base",
|
||||
"shadow-elevation-flyout dark:shadow-elevation-flyout-dark list-none"
|
||||
"mb-0 py-docs_0.25 overflow-auto rounded-docs_DEFAULT",
|
||||
"bg-medusa-bg-component text-medusa-fg-base",
|
||||
"shadow-elevation-flyout dark:shadow-elevation-flyout-dark list-none",
|
||||
"flex flex-col"
|
||||
)}
|
||||
>
|
||||
{addAll &&
|
||||
getSelectOption(
|
||||
{
|
||||
value: "all",
|
||||
label: "All Areas",
|
||||
isAllOption: true,
|
||||
},
|
||||
-1
|
||||
)}
|
||||
{addAll && (
|
||||
<>
|
||||
{getSelectOption(
|
||||
{
|
||||
value: "all",
|
||||
label: "All Areas",
|
||||
isAllOption: true,
|
||||
},
|
||||
-1
|
||||
)}
|
||||
{getDivider()}
|
||||
</>
|
||||
)}
|
||||
{options.map(getSelectOption)}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -79,6 +79,10 @@ export const useSelect = ({
|
||||
}
|
||||
}
|
||||
|
||||
const setSelectedValues = (values: string[]) => {
|
||||
setSelected?.(values)
|
||||
}
|
||||
|
||||
return {
|
||||
isValueSelected,
|
||||
hasSelectedValue,
|
||||
@@ -87,5 +91,6 @@ export const useSelect = ({
|
||||
isAllSelected,
|
||||
handleChange,
|
||||
handleSelectAll,
|
||||
setSelectedValues,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ export type AiAssistantContextType = {
|
||||
questionId: string,
|
||||
reaction: AiAssistantFeedbackType
|
||||
) => Promise<Response>
|
||||
version: "v1" | "v2"
|
||||
}
|
||||
|
||||
const AiAssistantContext = createContext<AiAssistantContextType | null>(null)
|
||||
@@ -22,12 +23,14 @@ export type AiAssistantProviderProps = {
|
||||
apiUrl: string
|
||||
recaptchaSiteKey: string
|
||||
websiteId: string
|
||||
version?: "v1" | "v2"
|
||||
}
|
||||
|
||||
export const AiAssistantProvider = ({
|
||||
apiUrl,
|
||||
recaptchaSiteKey,
|
||||
websiteId,
|
||||
version = "v2",
|
||||
children,
|
||||
}: AiAssistantProviderProps) => {
|
||||
const { analytics } = useAnalytics()
|
||||
@@ -90,6 +93,7 @@ export const AiAssistantProvider = ({
|
||||
value={{
|
||||
getAnswer,
|
||||
sendFeedback,
|
||||
version,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
|
||||
@@ -131,14 +131,9 @@ export const SearchProvider = ({
|
||||
<Modal
|
||||
contentClassName={clsx(
|
||||
"!p-0 overflow-hidden relative h-full",
|
||||
"rounded-none md:rounded-docs_lg flex flex-col justify-between"
|
||||
)}
|
||||
modalContainerClassName={clsx(
|
||||
"!rounded-none md:!rounded-docs_lg",
|
||||
"md:!h-[480px] h-screen",
|
||||
"md:!w-[640px] w-screen",
|
||||
"bg-medusa-bg-base"
|
||||
"flex flex-col justify-between"
|
||||
)}
|
||||
modalContainerClassName="sm:h-[480px] sm:max-h-[480px]"
|
||||
open={isOpen}
|
||||
onClose={() => setIsOpen(false)}
|
||||
passedRef={modalRef}
|
||||
@@ -156,7 +151,7 @@ export const SearchProvider = ({
|
||||
? "animate-fadeOutLeft animate-fast"
|
||||
: "animate-fadeOutRight animate-fast",
|
||||
}}
|
||||
timeout={300}
|
||||
timeout={250}
|
||||
key={command?.name || "search"}
|
||||
>
|
||||
<>
|
||||
|
||||
@@ -310,8 +310,14 @@ module.exports = {
|
||||
"inner-content-xxl": "640px",
|
||||
"inner-content-xxxl": "640px",
|
||||
// wide layout
|
||||
"wide-content": "1112px",
|
||||
"xl-wide-content": "1112px",
|
||||
"lg-wide-content": "800px",
|
||||
// modal
|
||||
"modal-xs": "304px",
|
||||
"modal-sm": "624px",
|
||||
"modal-md": "752px",
|
||||
"modal-lg": "640px",
|
||||
},
|
||||
minWidth: {
|
||||
xl: "1419px",
|
||||
|
||||
Reference in New Issue
Block a user