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