docs: create docs workspace (#5174)

* docs: migrate ui docs to docs universe

* created yarn workspace

* added eslint and tsconfig configurations

* fix eslint configurations

* fixed eslint configurations

* shared tailwind configurations

* added shared ui package

* added more shared components

* migrating more components

* made details components shared

* move InlineCode component

* moved InputText

* moved Loading component

* Moved Modal component

* moved Select components

* Moved Tooltip component

* moved Search components

* moved ColorMode provider

* Moved Notification components and providers

* used icons package

* use UI colors in api-reference

* moved Navbar component

* used Navbar and Search in UI docs

* added Feedback to UI docs

* general enhancements

* fix color mode

* added copy colors file from ui-preset

* added features and enhancements to UI docs

* move Sidebar component and provider

* general fixes and preparations for deployment

* update docusaurus version

* adjusted versions

* fix output directory

* remove rootDirectory property

* fix yarn.lock

* moved code component

* added vale for all docs MD and MDX

* fix tests

* fix vale error

* fix deployment errors

* change ignore commands

* add output directory

* fix docs test

* general fixes

* content fixes

* fix announcement script

* added changeset

* fix vale checks

* added nofilter option

* fix vale error
This commit is contained in:
Shahed Nasser
2023-09-21 20:57:15 +03:00
committed by GitHub
parent 19c5d5ba36
commit fa7c94b4cc
3209 changed files with 32188 additions and 31018 deletions

View File

@@ -0,0 +1,5 @@
---
"@medusajs/oas-github-ci": patch
---
feat(@medusajs/oas-github-ci): changed output path to match new docs workspace

View File

@@ -43,6 +43,6 @@ jobs:
base: "develop"
title: "chore(docs): Generated Docs Announcement Bar (automated)"
labels: "type: chore"
add-paths: www/docs/**
add-paths: www/apps/docs/**
branch: "chore/generate-announcement"
branch-suffix: "timestamp"

View File

@@ -41,6 +41,6 @@ jobs:
base: "develop"
title: "chore(docs): Removed Docs Announcement Bar (automated)"
labels: "type: chore"
add-paths: www/docs/**
add-paths: www/apps/docs/**
branch: "chore/remove-announcement"
branch-suffix: "timestamp"

View File

@@ -2,8 +2,8 @@ name: Documentation Tests
on:
pull_request:
paths:
- www/docs/**
- www/api-reference/**
- www/**
jobs:
docs-test:
runs-on: ubuntu-latest
@@ -29,17 +29,17 @@ jobs:
with:
extension: docs
- name: Install Docusaurus dependencies
working-directory: www/docs
- name: Install Workspace dependencies
working-directory: www
run: yarn install
- name: Build Docusaurus website
working-directory: www/docs
working-directory: www
env:
NODE_OPTIONS: "--max-old-space-size=8192"
API_URL: "https://docs.medusajs.com"
run: yarn build
run: yarn build:docs
lint:
vale-docs:
runs-on: ubuntu-latest
steps:
- name: Cancel Previous Runs
@@ -53,8 +53,8 @@ jobs:
fetch-depth: 0
- name: Get Directories to Scan
working-directory: www/docs/vale
run: ./get-files.sh
working-directory: www/vale
run: ./get-files.sh docs content references
id: directories
- name: Vale Linter
@@ -63,8 +63,71 @@ jobs:
files: ${{ steps.directories.outputs.LIST }}
fail_on_error: true
vale_flags: '--minAlertLevel=error'
reporter: github-pr-check
token: ${{ github.token }}
filter_mode: nofilter
env:
GITHUB_TOKEN: ${{ github.token }}
REVIEWDOG_GITHUB_API_TOKEN: ${{ github.token }}
vale-ui:
runs-on: ubuntu-latest
steps:
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.11.0
with:
access_token: ${{ github.token }}
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Get Directories to Scan
working-directory: www/vale
run: ./get-files.sh ui src/content/docs
id: directories
- name: Vale Linter
uses: errata-ai/vale-action@reviewdog
with:
files: ${{ steps.directories.outputs.LIST }}
fail_on_error: true
vale_flags: '--minAlertLevel=error'
reporter: github-pr-check
token: ${{ github.token }}
filter_mode: nofilter
env:
REVIEWDOG_GITHUB_API_TOKEN: ${{ github.token }}
vale-api:
runs-on: ubuntu-latest
steps:
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.11.0
with:
access_token: ${{ github.token }}
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Get Directories to Scan
working-directory: www/vale
run: ./get-files.sh api-reference app/_mdx
id: directories
- name: Vale Linter
uses: errata-ai/vale-action@reviewdog
with:
files: ${{ steps.directories.outputs.LIST }}
fail_on_error: true
vale_flags: '--minAlertLevel=error'
reporter: github-pr-check
token: ${{ github.token }}
filter_mode: nofilter
env:
REVIEWDOG_GITHUB_API_TOKEN: ${{ github.token }}
eslint:
runs-on: ubuntu-latest
@@ -80,11 +143,11 @@ jobs:
fetch-depth: 0
- name: Install dependencies
working-directory: www/docs
working-directory: www
run: yarn install
- name: Run Eslint
working-directory: www/docs
working-directory: www
run: yarn lint:content
code-docs-eslint:
@@ -104,33 +167,9 @@ jobs:
run: yarn install
- name: Install dependencies
working-directory: www/docs
working-directory: www
run: yarn install
- name: Run Eslint
working-directory: www/docs
run: yarn lint
code-api-ref-eslint:
runs-on: ubuntu-latest
steps:
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.11.0
with:
access_token: ${{ github.token }}
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Install Monorepo dependencies
run: yarn install
- name: Install dependencies
working-directory: www/api-reference
run: yarn install
- name: Run Eslint
working-directory: www/api-reference
working-directory: www
run: yarn lint

View File

@@ -43,6 +43,6 @@ jobs:
base: "develop"
title: "chore(docs): Updated API Reference"
labels: "type: chore"
add-paths: www/api-reference/specs
add-paths: www/apps/api-reference/specs
branch: "chore/generate-api-ref"
branch-suffix: "timestamp"

View File

@@ -42,6 +42,6 @@ jobs:
base: "develop"
title: "chore(docs): Generated Entities Reference (automated)"
labels: "type: chore"
add-paths: www/docs/content/references/entities/**
add-paths: www/apps/docs/content/references/entities/**
branch: "chore/generate-entities"
branch-suffix: "timestamp"

View File

@@ -42,6 +42,6 @@ jobs:
base: "develop"
title: "chore(docs): Generated JS Client Reference"
labels: "type: chore"
add-paths: www/docs/content/references/js-client/**
add-paths: www/apps/docs/content/references/js-client/**
branch: "chore/generate-js-client"
branch-suffix: "timestamp"

View File

@@ -42,6 +42,6 @@ jobs:
base: "develop"
title: "chore(docs): Generated Services Reference (automated)"
labels: "type: chore"
add-paths: www/docs/content/references/services/**
add-paths: www/apps/docs/content/references/services/**
branch: "chore/generate-services"
branch-suffix: "timestamp"

View File

@@ -1,4 +1,4 @@
StylesPath = www/docs/vale/styles
StylesPath = www/vale/styles
MinAlertLevel = suggestion
Vocab = Base

View File

@@ -8,7 +8,7 @@ const execa = require("execa")
const isDryRun = process.argv.indexOf("--dry-run") !== -1
const basePath = path.resolve(__dirname, `../`)
const repoRootPath = path.resolve(basePath, `../../../`)
const docsApiPath = path.resolve(repoRootPath, "www/api-reference/specs")
const docsApiPath = path.resolve(repoRootPath, "www/apps/api-reference/specs")
const run = async () => {
const oasOutDir = isDryRun ? await getTmpDirectory() : docsApiPath

View File

@@ -18,7 +18,7 @@ async function main () {
const commitResponse = await octokit.request('GET /repos/{owner}/{repo}/commits', {
owner: 'medusajs',
repo: 'medusa',
path: path.join('www', 'docs', 'announcement.json'),
path: path.join('www', "apps", 'docs', 'announcement.json'),
per_page: 1
})
@@ -47,7 +47,7 @@ async function main () {
}
//write new config file
fs.writeFileSync(path.join(__dirname, '..', 'www', 'docs', 'announcement.json'), JSON.stringify(announcement));
fs.writeFileSync(path.join(__dirname, '..', 'www', "apps", 'docs', 'announcement.json'), JSON.stringify(announcement));
console.log(`Announcement Bar has been ${shouldExpire ? 'removed' : 'added'}`);
}

View File

@@ -13,7 +13,7 @@ const linearClient = new LinearClient({
apiKey: process.env.LINEAR_API_KEY
});
const repoPath = path.join('docs', 'content');
const repoPath = path.join('www', 'apps', 'docs', 'content');
let freshnessCheckLabelId = "";
let documentationTeamId = "";

View File

@@ -3,7 +3,7 @@ const globalTypedocOptions = require("./typedoc")
module.exports = {
...globalTypedocOptions,
entryPoints: ["packages/medusa/src/models/index.ts"],
out: ["www/docs/content/references/entities"],
out: ["www/apps/docs/content/references/entities"],
tsconfig: "packages/medusa/tsconfig.json",
name: "Entities Reference",
indexTitle: "Entities Reference",

View File

@@ -4,7 +4,7 @@ module.exports = {
...globalTypedocOptions,
entryPoints: ["packages/medusa-js/src/resources"],
entryPointStrategy: "expand",
out: ["www/docs/content/references/js-client"],
out: ["www/apps/docs/content/references/js-client"],
tsconfig: "packages/medusa-js/tsconfig.json",
name: "JS Client Reference",
indexTitle: "JS Client Reference",

View File

@@ -3,7 +3,7 @@ const globalTypedocOptions = require("./typedoc")
module.exports = {
...globalTypedocOptions,
entryPoints: ["packages/medusa/src/services/index.ts"],
out: ["www/docs/content/references/services"],
out: ["www/apps/docs/content/references/services"],
tsconfig: "packages/medusa/tsconfig.json",
name: "Services Reference",
indexTitle: "Services Reference",

View File

@@ -1,127 +1,10 @@
module.exports = {
root: true,
parser: "@babel/eslint-parser",
parserOptions: {
requireConfigFile: false,
ecmaFeatures: {
experimentalDecorators: true,
jsx: true
},
},
plugins: [
"prettier"
],
extends: [
"eslint:recommended",
"plugin:prettier/recommended",
"plugin:react/recommended",
"plugin:react/jsx-runtime",
],
// This tells ESLint to load the config from the package `eslint-config-docs`
extends: ["docs"],
settings: {
react: {
version: "detect"
}
},
rules: {
curly: ["error", "all"],
"new-cap": "off",
"require-jsdoc": "off",
"no-unused-expressions": "off",
"no-unused-vars": "off",
camelcase: "off",
"no-invalid-this": "off",
"max-len": [
"error",
{
code: 80,
ignoreStrings: true,
ignoreRegExpLiterals: true,
ignoreComments: true,
ignoreTrailingComments: true,
ignoreUrls: true,
ignoreTemplateLiterals: true,
},
],
semi: ["error", "never"],
quotes: [
"error",
"double",
{
allowTemplateLiterals: true,
},
],
"comma-dangle": [
"error",
{
arrays: "always-multiline",
objects: "always-multiline",
imports: "always-multiline",
exports: "always-multiline",
functions: "never",
},
],
"object-curly-spacing": ["error", "always"],
"arrow-parens": ["error", "always"],
"linebreak-style": 0,
"no-confusing-arrow": [
"error",
{
allowParens: false,
},
],
"space-before-function-paren": [
"error",
{
anonymous: "always",
named: "never",
asyncArrow: "always",
},
],
"space-infix-ops": "error",
"eol-last": ["error", "always"],
"no-console": [
"error",
{
allow: [
"error",
"warn"
]
}
]
},
env: {
es6: true,
node: true,
jest: true,
browser: true,
},
ignorePatterns: [],
overrides: [
{
files: ["*.ts", "*.tsx", "*.js", "*.jsx"],
plugins: ["@typescript-eslint/eslint-plugin"],
extends: ["plugin:@typescript-eslint/recommended", "plugin:react/recommended"],
parser: "@typescript-eslint/parser",
parserOptions: {
project: "./tsconfig.json",
},
rules: {
"valid-jsdoc": "off",
"@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/no-floating-promises": "error",
"@typescript-eslint/await-thenable": "error",
"@typescript-eslint/promise-function-async": "error",
"@typescript-eslint/keyword-spacing": "error",
"@typescript-eslint/space-before-function-paren": [
"error",
{
anonymous: "always",
named: "never",
asyncArrow: "always",
},
],
"@typescript-eslint/space-infix-ops": "error",
},
next: {
rootDir: ["apps/*/"],
},
],
}
},
};

10
www/.gitignore vendored
View File

@@ -1,2 +1,10 @@
.vercel
build
build
node_modules
.yarn/*
.yarn/install-state.gz
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions

View File

@@ -1,4 +0,0 @@
next.config.js
specs
node_modules
public

View File

@@ -1,16 +0,0 @@
{
"extends": [
"next/core-web-vitals",
"google",
"../.eslintrc.js"
],
"rules": {
"react/react-in-jsx-scope": "off",
"@typescript-eslint/prefer-ts-expect-error": "off"
},
"settings": {
"next": {
"rootDir": "."
}
}
}

View File

@@ -1,21 +0,0 @@
import Feedback from "@/components/Feedback"
This API reference includes Medusa's Admin APIs, which are REST APIs exposed by the Medusa backend. They are typically used to perform admin functionalities or create an admin dashboard to access and manipulate your commerce store's data.
All endpoints are prefixed with `/admin`. So, during development, the endpoints will be available under the path `http://localhost:9000/admin`. For production, replace `http://localhost:9000` with your Medusa backend URL.
There are different ways you can send requests to these endpoints, including:
- Using Medusa's [JavaScript Client](https://docs.medusajs.com/js-client/overview)
- Using the [Medusa React](https://docs.medusajs.com/medusa-react/overview) library
- Using cURL
Aside from this API reference, check out the [Commerce Modules](https://docs.medusajs.com/modules/overview) section of the documentation for guides on how to use these APIs in different scenarios.
<Feedback
event="survey_api-ref"
extraData={{
area: "admin",
section: "introduction"
}}
/>

View File

@@ -1,21 +0,0 @@
import Feedback from "@/components/Feedback"
This API reference includes Medusa's Store APIs, which are REST APIs exposed by the Medusa backend. They are typically used to create a storefront for your commerce store, such as a webshop or a commerce mobile app.
All endpoints are prefixed with `/store`. So, during development, the endpoints will be available under the path `http://localhost:9000/store`. For production, replace `http://localhost:9000` with your Medusa backend URL.
There are different ways you can send requests to these endpoints, including:
- Using Medusa's [JavaScript Client](https://docs.medusajs.com/js-client/overview)
- Using the [Medusa React](https://docs.medusajs.com/medusa-react/overview) library
- Using cURL
Aside from this API reference, check out the [Commerce Modules](https://docs.medusajs.com/modules/overview) section of the documentation for guides on how to use these APIs in different scenarios.
<Feedback
event="survey_api-ref"
extraData={{
area: "store",
section: "introduction"
}}
/>

View File

@@ -1,81 +0,0 @@
import SidebarProvider from "@/providers/sidebar"
import Sidebar from "@/components/Sidebar"
import clsx from "clsx"
import "../../../css/globals.css"
import BaseSpecsProvider from "@/providers/base-specs"
import Navbar from "@/components/Navbar"
import ColorModeProvider from "@/providers/color-mode"
import { Inter } from "next/font/google"
import { Roboto_Mono } from "next/font/google"
import AnalyticsProvider from "@/providers/analytics"
import NavbarProvider from "@/providers/navbar"
import ModalProvider from "../../../providers/modal"
import SearchProvider from "../../../providers/search"
import { ScrollControllerProvider } from "../../../hooks/scroll-utils"
import MobileProvider from "../../../providers/mobile"
import PageLoadingProvider from "../../../providers/page-loading"
export const metadata = {
title: "Medusa API Reference",
description: "Check out Medusa's API reference",
}
const inter = Inter({
subsets: ["latin"],
variable: "--font-inter",
weight: ["400", "500"],
})
const robotoMono = Roboto_Mono({
subsets: ["latin"],
variable: "--font-roboto-mono",
})
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en" className={clsx("h-full w-full")}>
<body
className={clsx(
inter.variable,
robotoMono.variable,
"bg-docs-bg dark:bg-docs-bg-dark font-base text-medium h-full w-full",
"text-medusa-fg-subtle dark:text-medusa-fg-subtle-dark"
)}
>
<AnalyticsProvider>
<PageLoadingProvider>
<ModalProvider>
<ColorModeProvider>
<BaseSpecsProvider>
<SidebarProvider>
<NavbarProvider>
<ScrollControllerProvider>
<SearchProvider>
<MobileProvider>
<div className="w-full">
<Navbar />
<div className="max-w-xxl mx-auto flex w-full px-1.5">
<Sidebar />
<main className="lg:w-api-ref-main relative mt-4 w-full flex-1 lg:mt-7">
{children}
</main>
</div>
</div>
</MobileProvider>
</SearchProvider>
</ScrollControllerProvider>
</NavbarProvider>
</SidebarProvider>
</BaseSpecsProvider>
</ColorModeProvider>
</ModalProvider>
</PageLoadingProvider>
</AnalyticsProvider>
</body>
</html>
)
}

View File

@@ -1,53 +0,0 @@
import React from "react"
import clsx from "clsx"
export type BadgeProps = {
className?: string
variant:
| "purple"
| "purple-dark"
| "orange"
| "orange-dark"
| "green"
| "green-dark"
| "blue"
| "blue-dark"
| "red"
| "neutral"
} & React.HTMLAttributes<HTMLSpanElement>
const Badge: React.FC<BadgeProps> = ({ className, variant, children }) => {
return (
<span
className={clsx(
"text-compact-x-small-plus px-0.4 rounded-sm border border-solid py-px text-center",
variant === "purple" &&
"bg-medusa-tag-purple-bg dark:bg-medusa-tag-purple-bg-dark text-medusa-tag-purple-text dark:text-medusa-tag-purple-text-dark border-medusa-tag-purple-border dark:border-medusa-tag-purple-border-dark",
variant === "purple-dark" &&
"bg-medusa-tag-purple-bg-dark text-medusa-tag-purple-text-dark border-medusa-tag-purple-border-dark",
variant === "orange" &&
"bg-medusa-tag-orange-bg dark:bg-medusa-tag-orange-bg-dark text-medusa-tag-orange-text dark:text-medusa-tag-orange-text-dark border-medusa-tag-orange-border dark:border-medusa-tag-orange-border-dark",
variant === "orange-dark" &&
"bg-medusa-tag-orange-bg-dark text-medusa-tag-orange-text-dark border-medusa-tag-orange-border-dark",
variant === "green" &&
"bg-medusa-tag-green-bg dark:bg-medusa-tag-green-bg-dark text-medusa-tag-green-text dark:text-medusa-tag-green-text-dark border-medusa-tag-green-border dark:border-medusa-tag-green-border-dark",
variant === "green-dark" &&
"bg-medusa-tag-green-bg-dark text-medusa-tag-green-text-dark border-medusa-tag-green-border-dark",
variant === "blue" &&
"bg-medusa-tag-blue-bg dark:bg-medusa-tag-blue-bg-dark text-medusa-tag-blue-text dark:text-medusa-tag-blue-text-dark border-medusa-tag-blue-border dark:border-medusa-tag-blue-border-dark",
variant === "blue-dark" &&
"bg-medusa-tag-blue-bg-dark text-medusa-tag-blue-text-dark border-medusa-tag-blue-border-dark",
variant === "red" &&
"bg-medusa-tag-red-bg dark:bg-medusa-tag-red-bg-dark text-medusa-tag-red-text dark:text-medusa-tag-red-text-dark border-medusa-tag-red-border dark:border-medusa-tag-red-border-dark",
variant === "neutral" &&
"bg-medusa-tag-neutral-bg dark:bg-medusa-tag-neutral-bg-dark text-medusa-tag-neutral-text dark:text-medusa-tag-neutral-text-dark border-medusa-tag-neutral-border dark:border-medusa-tag-neutral-border-dark",
"badge",
className
)}
>
{children}
</span>
)
}
export default Badge

View File

@@ -1,56 +0,0 @@
import React from "react"
import clsx from "clsx"
import Bordered from "../Bordered/index"
import IconProps from "../Icons/types"
import { useColorMode } from "../../providers/color-mode"
import Image from "next/image"
type BorderedIconProp = {
icon?: {
light: string
dark?: string
}
IconComponent?: React.FC<IconProps>
wrapperClassName?: string
iconWrapperClassName?: string
iconClassName?: string
iconColorClassName?: string
} & React.HTMLAttributes<HTMLSpanElement>
const BorderedIcon: React.FC<BorderedIconProp> = ({
icon = null,
IconComponent = null,
wrapperClassName,
iconWrapperClassName,
iconClassName,
iconColorClassName = "",
}) => {
const { colorMode } = useColorMode()
return (
<Bordered wrapperClassName={wrapperClassName}>
<span
className={clsx(
"rounded-xs p-0.125 bg-medusa-bg-component dark:bg-medusa-bg-component-dark inline-flex items-center justify-center",
iconWrapperClassName
)}
>
{!IconComponent && (
<Image
src={(colorMode === "light" ? icon?.light : icon?.dark) || ""}
className={clsx(iconClassName, "bordered-icon")}
alt=""
/>
)}
{IconComponent && (
<IconComponent
className={clsx(iconClassName, "bordered-icon")}
iconColorClassName={iconColorClassName}
/>
)}
</span>
</Bordered>
)
}
export default BorderedIcon

View File

@@ -1,35 +0,0 @@
import clsx from "clsx"
export type ButtonProps = {
isSelected?: boolean
disabled?: boolean
variant?: "primary" | "secondary" | "clear"
darkVariant?: "primary" | "secondary" | "clear"
} & React.HTMLAttributes<HTMLButtonElement>
const Button = ({
className,
children,
variant = "primary",
darkVariant,
...props
}: ButtonProps) => {
return (
<button
className={clsx(
variant === "primary" && "btn-primary",
variant === "secondary" && "btn-secondary",
variant === "clear" && "btn-clear",
darkVariant && darkVariant === "primary" && "dark:btn-primary",
darkVariant && darkVariant === "secondary" && "dark:btn-secondary",
darkVariant && darkVariant === "clear" && "dark:btn-clear",
className
)}
{...props}
>
{children}
</button>
)
}
export default Button

View File

@@ -1,43 +0,0 @@
import clsx from "clsx"
import Link from "next/link"
import IconArrowUpRightOnBox from "../Icons/ArrowUpRightOnBox"
type CardProps = {
title: string
text?: string
href?: string
className?: string
}
const Card = ({ title, text, href, className }: CardProps) => {
return (
<div
className={clsx(
"bg-medusa-bg-subtle dark:bg-medusa-code-bg-base-dark w-full rounded",
"shadow-card-rest dark:shadow-card-rest-dark py-0.75 relative px-1",
"flex items-center justify-between gap-1 transition-shadow",
href && "hover:shadow-card-hover dark:hover:shadow-card-hover-dark",
className
)}
>
<div className="flex flex-col">
<span className="text-compact-medium-plus text-medusa-fg-base dark:text-medusa-fg-base-dark">
{title}
</span>
{text && <span className="text-compact-medium">{text}</span>}
</div>
{href && (
<>
<IconArrowUpRightOnBox />
<Link
href={href}
className="absolute left-0 top-0 h-full w-full rounded"
/>
</>
)}
</div>
)
}
export default Card

View File

@@ -1,54 +0,0 @@
"use client"
import { useState, useEffect, useRef, useCallback } from "react"
import clsx from "clsx"
import dynamic from "next/dynamic"
import { TooltipProps } from "../Tooltip"
import SpinnerLoading from "../Loading/Spinner"
const Tooltip = dynamic<TooltipProps>(async () => import("../Tooltip"), {
loading: () => <SpinnerLoading />,
}) as React.FC<TooltipProps>
export type CopyButtonProps = {
text: string
buttonClassName?: string
tooltipClassName?: string
} & React.HTMLAttributes<HTMLDivElement>
const CopyButton = ({
text,
buttonClassName = "",
tooltipClassName = "",
children,
}: CopyButtonProps) => {
const [isCopied, setIsCopied] = useState(false)
const copyTimeout = useRef<number | undefined>(undefined)
const handleCopy = useCallback(async () => {
const copy = (await import("copy-text-to-clipboard")).default
copy(text)
setIsCopied(true)
copyTimeout.current = window.setTimeout(() => {
setIsCopied(false)
}, 1000)
}, [text])
useEffect(() => () => window.clearTimeout(copyTimeout.current), [])
return (
<Tooltip
text={isCopied ? `Copied!` : `Copy to Clipboard`}
tooltipClassName={tooltipClassName}
>
<span
className={clsx("cursor-pointer", buttonClassName)}
onClick={handleCopy}
>
{children}
</span>
</Tooltip>
)
}
export default CopyButton

View File

@@ -1,207 +0,0 @@
"use client"
import React, { useRef, useState } from "react"
import { CSSTransition, SwitchTransition } from "react-transition-group"
import Solutions from "./Solutions/index"
import Button from "../Button"
import { ExtraData, useAnalytics } from "@/providers/analytics"
import { usePathname } from "next/navigation"
import Link from "next/link"
import { useArea } from "../../providers/area"
import clsx from "clsx"
import TextArea from "../TextArea"
import Label from "../Label"
type FeedbackProps = {
event: string
question?: string
positiveBtn?: string
negativeBtn?: string
positiveQuestion?: string
negativeQuestion?: string
submitBtn?: string
submitMessage?: string
showPossibleSolutions?: boolean
className?: string
extraData?: ExtraData
sectionTitle?: string
vertical?: boolean
} & React.HTMLAttributes<HTMLDivElement>
const Feedback: React.FC<FeedbackProps> = ({
event,
question = "Was this section helpful?",
positiveBtn = "Yes",
negativeBtn = "No",
positiveQuestion = "What was most helpful?",
negativeQuestion = "What can we improve?",
submitBtn = "Submit",
submitMessage = "Thank you for helping improve our documentation!",
showPossibleSolutions = true,
className = "",
extraData = {},
sectionTitle = "",
vertical = false,
}) => {
const [showForm, setShowForm] = useState(false)
const [submittedFeedback, setSubmittedFeedback] = useState(false)
const [loading, setLoading] = useState(false)
const inlineFeedbackRef = useRef<HTMLDivElement>(null)
const inlineQuestionRef = useRef<HTMLDivElement>(null)
const inlineMessageRef = useRef<HTMLDivElement>(null)
const [positiveFeedback, setPositiveFeedback] = useState(false)
const [message, setMessage] = useState("")
const nodeRef: React.RefObject<HTMLDivElement> = submittedFeedback
? inlineMessageRef
: showForm
? inlineQuestionRef
: inlineFeedbackRef
const pathname = usePathname()
const { loaded, track } = useAnalytics()
const { area } = useArea()
function handleFeedback(e: React.MouseEvent<HTMLButtonElement, MouseEvent>) {
if (!loaded) {
return
}
const feedback = (e.target as Element).classList.contains("positive")
setPositiveFeedback(feedback)
setShowForm(true)
submitFeedback(e, feedback)
}
function submitFeedback(
e: React.MouseEvent<HTMLButtonElement, MouseEvent>,
feedback = false
) {
if (showForm) {
setLoading(true)
}
track(
event,
{
url: pathname,
label: document.title,
feedback:
(feedback !== null && feedback) ||
(feedback === null && positiveFeedback)
? "yes"
: "no",
message: message?.length ? message : null,
os: window.navigator.userAgent,
...extraData,
},
function () {
if (showForm) {
setLoading(false)
resetForm()
}
}
)
}
function resetForm() {
setShowForm(false)
setSubmittedFeedback(true)
}
return (
<div className={clsx("mt-3", className)}>
<SwitchTransition mode="out-in">
<CSSTransition
key={
showForm
? "show_form"
: !submittedFeedback
? "feedback"
: "submitted_feedback"
}
nodeRef={nodeRef}
timeout={300}
addEndListener={(done) => {
nodeRef.current?.addEventListener("transitionend", done, false)
}}
classNames={{
enter: "animate-fadeIn animate-fill-forwards animate-fast",
exit: "animate-fadeOut animate-fill-forwards animate-fast",
}}
>
<>
{!showForm && !submittedFeedback && (
<div
className={clsx(
"flex",
!vertical && "flex-row items-center",
vertical && "flex-col justify-center gap-1"
)}
ref={inlineFeedbackRef}
>
<Label className="mr-1.5">{question}</Label>
<div className={clsx("flex flex-row items-center gap-0.5")}>
<Button
onClick={handleFeedback}
className="positive w-fit"
variant="secondary"
>
{positiveBtn}
</Button>
<Button
onClick={handleFeedback}
className="w-fit"
variant="secondary"
>
{negativeBtn}
</Button>
<Link
href={`https://github.com/medusajs/medusa/issues/new?assignees=&labels=type%3A+docs&template=docs.yml&title=API%20Ref%28${area}%29%3A%20Issue%20in%20${encodeURI(
sectionTitle
)}`}
className="btn-secondary"
>
Report Issue
</Link>
</div>
</div>
)}
{showForm && !submittedFeedback && (
<div className="flex flex-col gap-1" ref={inlineQuestionRef}>
<Label>
{positiveFeedback ? positiveQuestion : negativeQuestion}
</Label>
<TextArea
rows={4}
value={message}
onChange={(e) => setMessage(e.target.value)}
/>
<Button
onClick={submitFeedback}
disabled={loading}
className="w-fit"
variant="secondary"
>
{submitBtn}
</Button>
</div>
)}
{submittedFeedback && (
<div>
<div
className="text-compact-large-plus flex flex-col"
ref={inlineMessageRef}
>
<span>{submitMessage}</span>
{showPossibleSolutions && (
<Solutions message={message} feedback={positiveFeedback} />
)}
</div>
</div>
)}
</>
</CSSTransition>
</SwitchTransition>
</div>
)
}
export default Feedback

View File

@@ -1,26 +0,0 @@
import type IconProps from "../types"
const IconAlert = ({ iconColorClassName, ...props }: IconProps) => {
return (
<svg
width={props.width || 20}
height={props.height || 20}
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M18 10C18 12.1217 17.1571 14.1566 15.6569 15.6569C14.1566 17.1571 12.1217 18 10 18C7.87827 18 5.84344 17.1571 4.34315 15.6569C2.84285 14.1566 2 12.1217 2 10C2 7.87827 2.84285 5.84344 4.34315 4.34315C5.84344 2.84285 7.87827 2 10 2C12.1217 2 14.1566 2.84285 15.6569 4.34315C17.1571 5.84344 18 7.87827 18 10ZM10 5C10.1989 5 10.3897 5.07902 10.5303 5.21967C10.671 5.36032 10.75 5.55109 10.75 5.75V10.25C10.75 10.4489 10.671 10.6397 10.5303 10.7803C10.3897 10.921 10.1989 11 10 11C9.80109 11 9.61032 10.921 9.46967 10.7803C9.32902 10.6397 9.25 10.4489 9.25 10.25V5.75C9.25 5.55109 9.32902 5.36032 9.46967 5.21967C9.61032 5.07902 9.80109 5 10 5ZM10 15C10.2652 15 10.5196 14.8946 10.7071 14.7071C10.8946 14.5196 11 14.2652 11 14C11 13.7348 10.8946 13.4804 10.7071 13.2929C10.5196 13.1054 10.2652 13 10 13C9.73478 13 9.48043 13.1054 9.29289 13.2929C9.10536 13.4804 9 13.7348 9 14C9 14.2652 9.10536 14.5196 9.29289 14.7071C9.48043 14.8946 9.73478 15 10 15Z"
className={
iconColorClassName ||
"fill-medusa-fg-subtle dark:fill-medusa-fg-subtle-dark"
}
/>
</svg>
)
}
export default IconAlert

View File

@@ -1,37 +0,0 @@
import type IconProps from "../types"
const IconArrowDownLeftMini = ({ iconColorClassName, ...props }: IconProps) => {
return (
<svg
width={props.width || 20}
height={props.height || 20}
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
d="M8.00002 8.66675L4.66669 12.0001L8.00002 15.3334"
className={
iconColorClassName ||
"stroke-medusa-fg-subtle dark:stroke-medusa-fg-subtle-dark"
}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M15.3334 4.66675V9.33341C15.3334 10.0407 15.0524 10.7189 14.5523 11.219C14.0522 11.7191 13.3739 12.0001 12.6667 12.0001H4.66669"
className={
iconColorClassName ||
"stroke-medusa-fg-subtle dark:stroke-medusa-fg-subtle-dark"
}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
)
}
export default IconArrowDownLeftMini

View File

@@ -1,27 +0,0 @@
import type IconProps from "../types"
const IconArrowUpRightOnBox = ({ iconColorClassName, ...props }: IconProps) => {
return (
<svg
width={props.width || 20}
height={props.height || 20}
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
d="M9.55356 5.32683H5.24268C4.7779 5.32683 4.33216 5.51146 4.00351 5.84011C3.67487 6.16875 3.49023 6.6145 3.49023 7.07927V15.2574C3.49023 15.7221 3.67487 16.1679 4.00351 16.4965C4.33216 16.8252 4.7779 17.0098 5.24268 17.0098H13.4208C13.8855 17.0098 14.3313 16.8252 14.6599 16.4965C14.9886 16.1679 15.1732 15.7221 15.1732 15.2574V11.0207M7.50323 13.0137L17.5098 2.99023M17.5098 2.99023H13.4208M17.5098 2.99023V7.07927"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
className={
iconColorClassName ||
"stroke-medusa-fg-subtle dark:stroke-medusa-fg-subtle-dark"
}
/>
</svg>
)
}
export default IconArrowUpRightOnBox

View File

@@ -1,28 +0,0 @@
import React from "react"
import IconProps from "../types"
const IconBarsThree = ({ iconColorClassName, ...props }: IconProps) => {
return (
<svg
width={props.width || 20}
height={props.height || 20}
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
d="M3.125 5.00006H16.875M3.125 10H16.875M3.125 15.0001H16.875"
className={
iconColorClassName ||
"stroke-medusa-fg-subtle dark:stroke-medusa-fg-subtle-dark"
}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
)
}
export default IconBarsThree

View File

@@ -1,32 +0,0 @@
import type IconProps from "../types"
const IconCheckMini = ({
iconColorClassName,
containerClassName,
...props
}: IconProps) => {
return (
<svg
width={props.width || 20}
height={props.height || 20}
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className={containerClassName}
{...props}
>
<path
d="M5.83334 10.4167L9.16668 13.75L14.1667 6.25"
className={
iconColorClassName ||
"stroke-medusa-fg-subtle dark:stroke-medusa-fg-subtle-dark"
}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
)
}
export default IconCheckMini

View File

@@ -1,27 +0,0 @@
import type IconProps from "../types"
const IconChevronDownMini = ({ iconColorClassName, ...props }: IconProps) => {
return (
<svg
width={props.width || 20}
height={props.height || 20}
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
d="M15 8L10 13L5 8"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
className={
iconColorClassName ||
"stroke-medusa-fg-subtle dark:stroke-medusa-fg-subtle-dark"
}
/>
</svg>
)
}
export default IconChevronDownMini

View File

@@ -1,32 +0,0 @@
import type IconProps from "../types"
const IconChevronRightMini = ({
iconColorClassName,
containerClassName,
...props
}: IconProps) => {
return (
<svg
width={props.width || 20}
height={props.height || 20}
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className={containerClassName}
{...props}
>
<path
d="M8 6L12 10L8 14"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
className={
iconColorClassName ||
"stroke-medusa-fg-subtle dark:stroke-medusa-fg-subtle-dark"
}
/>
</svg>
)
}
export default IconChevronRightMini

View File

@@ -1,32 +0,0 @@
import type IconProps from "../types"
const IconChevronUpDown = ({
iconColorClassName,
containerClassName,
...props
}: IconProps) => {
return (
<svg
width={props.width || 20}
height={props.height || 20}
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className={containerClassName}
{...props}
>
<path
d="M6 12.75L9.75 16.5L13.5 12.75M6 6.75L9.75 3L13.5 6.75"
className={
iconColorClassName ||
"stroke-medusa-fg-subtle dark:stroke-medusa-fg-subtle-dark"
}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
)
}
export default IconChevronUpDown

View File

@@ -1,31 +0,0 @@
import IconProps from "../types"
const IconCopy = ({ iconColorClassName, ...props }: IconProps) => {
return (
<svg
width={props.width || 20}
height={props.height || 20}
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
d="M2 4.25C2 3.65326 2.23705 3.08097 2.65901 2.65901C3.08097 2.23705 3.65326 2 4.25 2H10.75C11.3467 2 11.919 2.23705 12.341 2.65901C12.7629 3.08097 13 3.65326 13 4.25V5.5H9.25C8.25544 5.5 7.30161 5.89509 6.59835 6.59835C5.89509 7.30161 5.5 8.25544 5.5 9.25V13H4.25C3.65326 13 3.08097 12.7629 2.65901 12.341C2.23705 11.919 2 11.3467 2 10.75V4.25Z"
className={
iconColorClassName ||
"fill-medusa-fg-subtle dark:fill-medusa-fg-subtle-dark"
}
/>
<path
d="M9.25 7C8.65326 7 8.08097 7.23705 7.65901 7.65901C7.23705 8.08097 7 8.65326 7 9.25V15.75C7 16.3467 7.23705 16.919 7.65901 17.341C8.08097 17.7629 8.65326 18 9.25 18H15.75C16.3467 18 16.919 17.7629 17.341 17.341C17.7629 16.919 18 16.3467 18 15.75V9.25C18 8.65326 17.7629 8.08097 17.341 7.65901C16.919 7.23705 16.3467 7 15.75 7H9.25Z"
className={
iconColorClassName ||
"fill-medusa-fg-subtle dark:fill-medusa-fg-subtle-dark"
}
/>
</svg>
)
}
export default IconCopy

View File

@@ -1,28 +0,0 @@
import React from "react"
import IconProps from "../types"
const IconCopyOutline = ({ iconColorClassName, ...props }: IconProps) => {
return (
<svg
width={props.width || 20}
height={props.height || 20}
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
d="M13.75 6.875V5C13.75 4.50272 13.5525 4.02581 13.2008 3.67417C12.8492 3.32254 12.3723 3.125 11.875 3.125H5C4.50272 3.125 4.02581 3.32254 3.67417 3.67417C3.32254 4.02581 3.125 4.50272 3.125 5V11.875C3.125 12.3723 3.32254 12.8492 3.67417 13.2008C4.02581 13.5525 4.50272 13.75 5 13.75H6.875M13.75 6.875H15C15.4973 6.875 15.9742 7.07254 16.3258 7.42417C16.6775 7.77581 16.875 8.25272 16.875 8.75V15C16.875 15.4973 16.6775 15.9742 16.3258 16.3258C15.9742 16.6775 15.4973 16.875 15 16.875H8.75C8.25272 16.875 7.77581 16.6775 7.42417 16.3258C7.07254 15.9742 6.875 15.4973 6.875 15V13.75M13.75 6.875H8.75C8.25272 6.875 7.77581 7.07254 7.42417 7.42417C7.07254 7.77581 6.875 8.25272 6.875 8.75V13.75"
className={
iconColorClassName ||
"stroke-medusa-fg-subtle dark:stroke-medusa-fg-subtle-dark"
}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
)
}
export default IconCopyOutline

View File

@@ -1,27 +0,0 @@
import type IconProps from "../types"
const IconDarkMode = ({ iconColorClassName, ...props }: IconProps) => {
return (
<svg
width={props.width || 20}
height={props.height || 20}
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
d="M18.1267 12.5017C17.136 12.9147 16.0732 13.1265 15 13.1251C10.5125 13.1251 6.875 9.48758 6.875 5.00008C6.875 3.89175 7.09667 2.83591 7.49833 1.87341C6.01789 2.49101 4.75331 3.53287 3.86386 4.86779C2.9744 6.20271 2.49986 7.77098 2.5 9.37508C2.5 13.8626 6.1375 17.5001 10.625 17.5001C12.2291 17.5002 13.7974 17.0257 15.1323 16.1362C16.4672 15.2468 17.5091 13.9822 18.1267 12.5017Z"
className={
iconColorClassName ||
"stroke-medusa-fg-subtle dark:stroke-medusa-fg-subtle-dark"
}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
)
}
export default IconDarkMode

View File

@@ -1,33 +0,0 @@
import IconProps from "../types"
const IconDocumentTextSolid = ({ iconColorClassName, ...props }: IconProps) => {
return (
<svg
width={props.width || 20}
height={props.height || 20}
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M4.91521 1.625C4.08888 1.625 3.41968 2.295 3.41968 3.12054V16.8795C3.41968 17.705 4.08968 18.375 4.91521 18.375H15.0849C15.9104 18.375 16.5804 17.705 16.5804 16.8795V10.5982C16.5804 9.80493 16.2653 9.04414 15.7043 8.48321C15.1434 7.92227 14.3826 7.60714 13.5893 7.60714H12.0938C11.6971 7.60714 11.3167 7.44958 11.0363 7.16911C10.7558 6.88864 10.5982 6.50825 10.5982 6.11161V4.61607C10.5982 3.82279 10.2831 3.062 9.72218 2.50106C9.16125 1.94013 8.40046 1.625 7.60718 1.625H4.91521ZM6.41075 12.3929C6.41075 12.2342 6.47378 12.082 6.58596 11.9699C6.69815 11.8577 6.85031 11.7946 7.00896 11.7946H12.9911C13.1498 11.7946 13.3019 11.8577 13.4141 11.9699C13.5263 12.082 13.5893 12.2342 13.5893 12.3929C13.5893 12.5515 13.5263 12.7037 13.4141 12.8159C13.3019 12.928 13.1498 12.9911 12.9911 12.9911H7.00896C6.85031 12.9911 6.69815 12.928 6.58596 12.8159C6.47378 12.7037 6.41075 12.5515 6.41075 12.3929ZM7.00896 14.1875C6.85031 14.1875 6.69815 14.2505 6.58596 14.3627C6.47378 14.4749 6.41075 14.6271 6.41075 14.7857C6.41075 14.9444 6.47378 15.0965 6.58596 15.2087C6.69815 15.3209 6.85031 15.3839 7.00896 15.3839H10C10.1587 15.3839 10.3108 15.3209 10.423 15.2087C10.5352 15.0965 10.5982 14.9444 10.5982 14.7857C10.5982 14.6271 10.5352 14.4749 10.423 14.3627C10.3108 14.2505 10.1587 14.1875 10 14.1875H7.00896Z"
className={
iconColorClassName ||
"fill-medusa-fg-subtle dark:fill-medusa-fg-subtle-dark"
}
/>
<path
d="M10.7745 1.8772C11.4338 2.6373 11.7961 3.61006 11.7947 4.61622V6.11176C11.7947 6.27686 11.9287 6.41086 12.0938 6.41086H13.5893C14.5955 6.40947 15.5683 6.77177 16.3284 7.43102C15.9774 6.09637 15.2783 4.87888 14.3025 3.90306C13.3267 2.92724 12.1092 2.22812 10.7745 1.8772Z"
className={
iconColorClassName ||
"fill-medusa-fg-subtle dark:fill-medusa-fg-subtle-dark"
}
/>
</svg>
)
}
export default IconDocumentTextSolid

View File

@@ -1,31 +0,0 @@
import type IconProps from "../types"
const IconEllipseMiniSolid = ({
iconColorClassName,
containerClassName,
...props
}: IconProps) => {
return (
<svg
width={props.width || 20}
height={props.height || 20}
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className={containerClassName}
{...props}
>
<circle
cx="10"
cy="10"
r="2"
className={
iconColorClassName ||
"fill-medusa-fg-subtle dark:fill-medusa-fg-subtle-dark"
}
/>
</svg>
)
}
export default IconEllipseMiniSolid

View File

@@ -1,29 +0,0 @@
import IconProps from "../types"
const IconExclamationCircleSolid = ({
iconColorClassName,
...props
}: IconProps) => {
return (
<svg
width={props.width || 20}
height={props.height || 20}
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M18 10C18 12.1217 17.1571 14.1566 15.6569 15.6569C14.1566 17.1571 12.1217 18 10 18C7.87827 18 5.84344 17.1571 4.34315 15.6569C2.84285 14.1566 2 12.1217 2 10C2 7.87827 2.84285 5.84344 4.34315 4.34315C5.84344 2.84285 7.87827 2 10 2C12.1217 2 14.1566 2.84285 15.6569 4.34315C17.1571 5.84344 18 7.87827 18 10ZM10 5C10.1989 5 10.3897 5.07902 10.5303 5.21967C10.671 5.36032 10.75 5.55109 10.75 5.75V10.25C10.75 10.4489 10.671 10.6397 10.5303 10.7803C10.3897 10.921 10.1989 11 10 11C9.80109 11 9.61032 10.921 9.46967 10.7803C9.32902 10.6397 9.25 10.4489 9.25 10.25V5.75C9.25 5.55109 9.32902 5.36032 9.46967 5.21967C9.61032 5.07902 9.80109 5 10 5ZM10 15C10.2652 15 10.5196 14.8946 10.7071 14.7071C10.8946 14.5196 11 14.2652 11 14C11 13.7348 10.8946 13.4804 10.7071 13.2929C10.5196 13.1054 10.2652 13 10 13C9.73478 13 9.48043 13.1054 9.29289 13.2929C9.10536 13.4804 9 13.7348 9 14C9 14.2652 9.10536 14.5196 9.29289 14.7071C9.48043 14.8946 9.73478 15 10 15Z"
className={
iconColorClassName ||
"fill-medusa-fg-subtle dark:fill-medusa-fg-subtle-dark"
}
/>
</svg>
)
}
export default IconExclamationCircleSolid

View File

@@ -1,27 +0,0 @@
import type IconProps from "../types"
const IconLightMode = ({ iconColorClassName, ...props }: IconProps) => {
return (
<svg
width={props.width || 20}
height={props.height || 20}
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
d="M10 2.5V4.375M15.3033 4.69667L13.9775 6.0225M17.5 10H15.625M15.3033 15.3033L13.9775 13.9775M10 15.625V17.5M6.0225 13.9775L4.69667 15.3033M4.375 10H2.5M6.0225 6.0225L4.69667 4.69667M13.125 10C13.125 10.8288 12.7958 11.6237 12.2097 12.2097C11.6237 12.7958 10.8288 13.125 10 13.125C9.1712 13.125 8.37634 12.7958 7.79029 12.2097C7.20424 11.6237 6.875 10.8288 6.875 10C6.875 9.1712 7.20424 8.37634 7.79029 7.79029C8.37634 7.20424 9.1712 6.875 10 6.875C10.8288 6.875 11.6237 7.20424 12.2097 7.79029C12.7958 8.37634 13.125 9.1712 13.125 10Z"
className={
iconColorClassName ||
"stroke-medusa-fg-subtle dark:stroke-medusa-fg-subtle-dark"
}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
)
}
export default IconLightMode

View File

@@ -1,27 +0,0 @@
import type IconProps from "../types"
const IconMagnifyingGlass = ({ iconColorClassName, ...props }: IconProps) => {
return (
<svg
width={props.width || 20}
height={props.height || 20}
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
d="M17.4999 17.8713L13.1691 13.5404M13.1691 13.5404C14.3412 12.3683 14.9997 10.7785 14.9997 9.12084C14.9997 7.46317 14.3412 5.8734 13.1691 4.70126C11.9969 3.52911 10.4072 2.87061 8.7495 2.87061C7.09184 2.87061 5.50207 3.52911 4.32992 4.70126C3.15777 5.8734 2.49927 7.46317 2.49927 9.12084C2.49927 10.7785 3.15777 12.3683 4.32992 13.5404C5.50207 14.7126 7.09184 15.3711 8.7495 15.3711C10.4072 15.3711 11.9969 14.7126 13.1691 13.5404V13.5404Z"
className={
iconColorClassName ||
"stroke-medusa-fg-subtle dark:stroke-medusa-fg-subtle-dark"
}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
)
}
export default IconMagnifyingGlass

View File

@@ -1,25 +0,0 @@
import type IconProps from "../types"
const IconMedusa = ({ iconColorClassName, ...props }: IconProps) => {
return (
<svg
width={props.width || 20}
height={props.height || 20}
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
d="M16.2447 3.92183L12.1688 1.57686C10.8352 0.807712 9.20112 0.807712 7.86753 1.57686L3.77285 3.92183C2.45804 4.69098 1.63159 6.11673 1.63159 7.63627V12.345C1.63159 13.8833 2.45804 15.2903 3.77285 16.0594L7.84875 18.4231C9.18234 19.1923 10.8165 19.1923 12.15 18.4231L16.2259 16.0594C17.5595 15.2903 18.3672 13.8833 18.3672 12.345V7.63627C18.4048 6.11673 17.5783 4.69098 16.2447 3.92183ZM10.0088 14.1834C7.69849 14.1834 5.82019 12.3075 5.82019 10C5.82019 7.69255 7.69849 5.81657 10.0088 5.81657C12.3191 5.81657 14.2162 7.69255 14.2162 10C14.2162 12.3075 12.3379 14.1834 10.0088 14.1834Z"
fill="#030712"
className={
iconColorClassName ||
"fill-medusa-fg-subtle dark:fill-medusa-fg-subtle-dark"
}
/>
</svg>
)
}
export default IconMedusa

View File

@@ -1,27 +0,0 @@
import type IconProps from "../types"
const IconMinusMini = ({ iconColorClassName, ...props }: IconProps) => {
return (
<svg
width={props.width || 20}
height={props.height || 20}
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
d="M14.375 10H5.62498"
className={
iconColorClassName ||
"stroke-medusa-fg-subtle dark:stroke-medusa-fg-subtle-dark"
}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
)
}
export default IconMinusMini

View File

@@ -1,27 +0,0 @@
import type IconProps from "../types"
const IconPlusMini = ({ iconColorClassName, ...props }: IconProps) => {
return (
<svg
width={props.width || 20}
height={props.height || 20}
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
d="M10.5 5V15M15.5 10H5.5"
className={
iconColorClassName ||
"stroke-medusa-fg-subtle dark:stroke-medusa-fg-subtle-dark"
}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
)
}
export default IconPlusMini

View File

@@ -1,47 +0,0 @@
import type IconProps from "../types"
const IconReport = ({ iconColorClassName, ...props }: IconProps) => {
return (
<svg
width={props.width || 20}
height={props.height || 20}
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
d="M10 17.5C14.1421 17.5 17.5 14.1421 17.5 10C17.5 5.85786 14.1421 2.5 10 2.5C5.85786 2.5 2.5 5.85786 2.5 10C2.5 14.1421 5.85786 17.5 10 17.5Z"
className={
iconColorClassName ||
"stroke-medusa-fg-subtle dark:stroke-medusa-fg-subtle-dark"
}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M10 6.6665V9.99984"
className={
iconColorClassName ||
"stroke-medusa-fg-subtle dark:stroke-medusa-fg-subtle-dark"
}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M10 13.3335H10.0088"
className={
iconColorClassName ||
"stroke-medusa-fg-subtle dark:stroke-medusa-fg-subtle-dark"
}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
)
}
export default IconReport

View File

@@ -1,27 +0,0 @@
import type IconProps from "../types"
const IconSidebar = ({ iconColorClassName, ...props }: IconProps) => {
return (
<svg
width={props.width || 20}
height={props.height || 20}
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
d="M9 3.125H4.375C3.87772 3.125 3.40081 3.32254 3.04917 3.67417C2.69754 4.02581 2.5 4.50272 2.5 5V6.875V15C2.5 15.4973 2.69754 15.9742 3.04917 16.3258C3.40081 16.6775 3.87772 16.875 4.375 16.875H9M9 3.125H15.625C16.1223 3.125 16.5992 3.32254 16.9508 3.67417C17.3025 4.02581 17.5 4.50272 17.5 5V6.875V15C17.5 15.4973 17.3025 15.9742 16.9508 16.3258C16.5992 16.6775 16.1223 16.875 15.625 16.875H9M9 3.125V16.875M5 6.5H6.5M5 9.5H6.5"
className={
iconColorClassName ||
"stroke-medusa-fg-subtle dark:stroke-medusa-fg-subtle-dark"
}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
)
}
export default IconSidebar

View File

@@ -1,24 +0,0 @@
import type IconProps from "../types"
const IconSpinner = ({ iconColorClassName, ...props }: IconProps) => {
return (
<svg
width={props.width || 20}
height={props.height || 20}
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
d="M14.8649 14.8649C15.3023 15.3023 15.3063 16.0188 14.8121 16.3909C14.0399 16.9723 13.1661 17.4109 12.2319 17.6823C10.9379 18.0583 9.56991 18.1013 8.25485 17.8073C6.93979 17.5134 5.72029 16.892 4.7095 16.0009C3.69872 15.1098 2.92941 13.9778 2.47295 12.7099C2.0165 11.4421 1.8877 10.0794 2.09849 8.74852C2.30929 7.4176 2.85286 6.16149 3.67876 5.09674C4.50466 4.032 5.58613 3.19312 6.82282 2.65796C7.71563 2.27161 8.66846 2.05258 9.6341 2.00837C10.252 1.98008 10.7057 2.53472 10.6475 3.15053C10.5893 3.76635 10.0393 4.20701 9.42382 4.26889C8.83606 4.32798 8.25864 4.47736 7.71243 4.71373C6.82201 5.09905 6.04336 5.70304 5.44871 6.46966C4.85406 7.23627 4.46269 8.14067 4.31091 9.09894C4.15914 10.0572 4.25188 11.0383 4.58053 11.9511C4.90917 12.864 5.46308 13.679 6.19084 14.3206C6.91861 14.9623 7.79665 15.4096 8.74349 15.6213C9.69034 15.8329 10.6753 15.802 11.607 15.5313C12.1785 15.3652 12.7186 15.1123 13.2092 14.7832C13.7229 14.4385 14.4275 14.4275 14.8649 14.8649Z"
className={
iconColorClassName ||
"fill-medusa-fg-subtle dark:fill-medusa-fg-subtle-dark"
}
/>
</svg>
)
}
export default IconSpinner

View File

@@ -1,42 +0,0 @@
import IconProps from "../types"
const IconToolsSolid = ({ iconColorClassName, ...props }: IconProps) => {
return (
<svg
width={props.width || 20}
height={props.height || 20}
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M9.99753 6.06351C9.99737 5.44855 10.1413 4.84211 10.4177 4.29277C10.6941 3.74343 11.0953 3.26648 11.5893 2.90013C12.0832 2.53379 12.6561 2.28824 13.262 2.18315C13.8679 2.07807 14.49 2.11638 15.0784 2.29501C15.1714 2.32318 15.2556 2.37498 15.3226 2.44534C15.3896 2.5157 15.4373 2.60222 15.4609 2.69649C15.4846 2.79075 15.4834 2.88952 15.4575 2.98319C15.4316 3.07686 15.3819 3.16222 15.3132 3.23095L12.8233 5.72003C12.8706 6.07626 13.0303 6.42049 13.3041 6.69422C13.5778 6.96795 13.922 7.12769 14.279 7.17419L16.7673 4.6851C16.8361 4.6164 16.9214 4.56668 17.0151 4.54078C17.1088 4.51489 17.2075 4.5137 17.3018 4.53734C17.3961 4.56099 17.4826 4.60864 17.5529 4.67568C17.6233 4.74271 17.6751 4.82683 17.7033 4.91984C17.8902 5.53544 17.9234 6.18746 17.8 6.81886C17.6766 7.45026 17.4003 8.0418 16.9954 8.54174C16.5905 9.04167 16.0692 9.43477 15.4772 9.68663C14.8852 9.93849 14.2405 10.0415 13.5995 9.9865C12.8361 9.92201 12.1971 10.0615 11.8679 10.462L6.50576 16.9753C6.2862 17.2406 6.01366 17.4571 5.70559 17.611C5.39752 17.7649 5.06071 17.8528 4.71672 17.869C4.37273 17.8852 4.02915 17.8294 3.70797 17.7052C3.38679 17.5809 3.0951 17.391 2.85157 17.1475C2.60803 16.904 2.41803 16.6124 2.29372 16.2912C2.16941 15.9701 2.11353 15.6265 2.12967 15.2825C2.14581 14.9385 2.2336 14.6017 2.38743 14.2936C2.54126 13.9855 2.75773 13.7129 3.02299 13.4933L9.53556 8.13037C9.93528 7.8004 10.0755 7.16219 10.011 6.39874C10.0018 6.28723 9.99734 6.17539 9.99753 6.06351ZM4.08567 15.3442C4.08567 15.195 4.14493 15.0519 4.25041 14.9464C4.35589 14.8409 4.49895 14.7817 4.64813 14.7817H4.65413C4.8033 14.7817 4.94637 14.8409 5.05185 14.9464C5.15733 15.0519 5.21659 15.195 5.21659 15.3442V15.3501C5.21659 15.4993 5.15733 15.6424 5.05185 15.7479C4.94637 15.8534 4.8033 15.9126 4.65413 15.9126H4.64813C4.49895 15.9126 4.35589 15.8534 4.25041 15.7479C4.14493 15.6424 4.08567 15.4993 4.08567 15.3501V15.3442Z"
className={
iconColorClassName ||
"fill-medusa-fg-subtle dark:fill-medusa-fg-subtle-dark"
}
/>
<path
d="M8.55462 7.48082L6.90398 5.83093V4.65651C6.90397 4.5594 6.87883 4.46395 6.83099 4.37945C6.78315 4.29495 6.71425 4.22427 6.631 4.17429L3.81868 2.4869C3.71112 2.42242 3.58509 2.39574 3.46063 2.41109C3.33616 2.42645 3.2204 2.48296 3.13173 2.57164L2.56926 3.13411C2.48058 3.22278 2.42407 3.33854 2.40871 3.46301C2.39336 3.58747 2.42004 3.7135 2.48452 3.82106L4.17191 6.63338C4.22189 6.71663 4.29257 6.78553 4.37707 6.83337C4.46157 6.88121 4.55702 6.90635 4.65413 6.90636H5.82705L7.37345 8.45276L8.55462 7.48007V7.48082Z"
className={
iconColorClassName ||
"fill-medusa-fg-subtle dark:fill-medusa-fg-subtle-dark"
}
/>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M10.4146 13.9971L13.5516 17.1334C13.7866 17.3685 14.0657 17.5549 14.3727 17.6821C14.6798 17.8093 15.009 17.8748 15.3414 17.8748C15.6737 17.8748 16.0029 17.8093 16.31 17.6821C16.617 17.5549 16.8961 17.3685 17.1311 17.1334C17.3661 16.8984 17.5526 16.6194 17.6798 16.3123C17.807 16.0052 17.8724 15.6761 17.8724 15.3437C17.8724 15.0113 17.807 14.6821 17.6798 14.3751C17.5526 14.068 17.3661 13.7889 17.1311 13.5539L14.6518 11.0753C14.2717 11.1292 13.8868 11.14 13.5043 11.1076C13.2089 11.0821 12.9929 11.1031 12.8541 11.1391C12.8102 11.1484 12.768 11.1643 12.7289 11.1863L10.4146 13.9971ZM12.9749 12.9772C13.0803 12.8719 13.2233 12.8127 13.3724 12.8127C13.5214 12.8127 13.6644 12.8719 13.7698 12.9772L15.176 14.3841C15.2312 14.4356 15.2756 14.4977 15.3063 14.5667C15.3371 14.6357 15.3536 14.7102 15.3549 14.7857C15.3563 14.8612 15.3424 14.9362 15.3141 15.0063C15.2858 15.0763 15.2437 15.1399 15.1903 15.1933C15.1369 15.2467 15.0732 15.2888 15.0032 15.3171C14.9332 15.3454 14.8581 15.3593 14.7826 15.358C14.7071 15.3566 14.6326 15.3401 14.5636 15.3094C14.4946 15.2786 14.4325 15.2343 14.381 15.179L12.9749 13.7729C12.8696 13.6674 12.8104 13.5245 12.8104 13.3754C12.8104 13.2264 12.8696 13.0834 12.9749 12.9779V12.9772Z"
className={
iconColorClassName ||
"fill-medusa-fg-subtle dark:fill-medusa-fg-subtle-dark"
}
/>
</svg>
)
}
export default IconToolsSolid

View File

@@ -1,36 +0,0 @@
import IconProps from "../types"
const IconTreeNode = ({ iconColorClassName, ...props }: IconProps) => {
return (
<svg
width={props.width || 16}
height={props.height || 32}
viewBox="0 0 16 32"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<rect
width="1"
height="32"
rx="0.5"
className={
iconColorClassName ||
"fill-medusa-fg-subtle dark:fill-medusa-fg-subtle-dark"
}
/>
<rect
y="15.5"
width="16"
height="1"
rx="0.5"
className={
iconColorClassName ||
"fill-medusa-fg-subtle dark:fill-medusa-fg-subtle-dark"
}
/>
</svg>
)
}
export default IconTreeNode

View File

@@ -1,27 +0,0 @@
import IconProps from "../types"
const IconXMark = ({ iconColorClassName, ...props }: IconProps) => {
return (
<svg
width={props.width || 20}
height={props.height || 20}
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
d="M5 15L15 5M5 5L15 15"
className={
iconColorClassName ||
"stroke-medusa-fg-subtle dark:stroke-medusa-fg-subtle-dark"
}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
)
}
export default IconXMark

View File

@@ -1,27 +0,0 @@
import IconProps from "../types"
const IconXMarkMini = ({ iconColorClassName, ...props }: IconProps) => {
return (
<svg
width={props.width || 20}
height={props.height || 20}
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
{...props}
>
<path
d="M6 14L14 6M6 6L14 14"
className={
iconColorClassName ||
"stroke-medusa-fg-subtle dark:stroke-medusa-fg-subtle-dark"
}
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
)
}
export default IconXMarkMini

View File

@@ -1,6 +0,0 @@
type IconProps = {
iconColorClassName?: string
containerClassName?: string
} & React.AllHTMLAttributes<SVGElement>
export default IconProps

View File

@@ -1,45 +0,0 @@
import { CopyButtonProps } from "@/components/CopyButton"
import clsx from "clsx"
import dynamic from "next/dynamic"
import SpinnerLoading from "../Loading/Spinner"
const CopyButton = dynamic<CopyButtonProps>(
async () => import("../CopyButton"),
{
loading: () => <SpinnerLoading />,
}
) as React.FC<CopyButtonProps>
export type InlineCodeProps = React.ComponentProps<"code">
const InlineCode = (props: InlineCodeProps) => {
const isInline = typeof props.children === "string"
return (
<>
{!isInline && <code {...props} />}
{isInline && (
<CopyButton
text={props.children as string}
buttonClassName={clsx(
"bg-transparent border-0 p-0 inline text-medusa-fg-subtle dark:text-medusa-fg-subtle-dark",
"active:[&>code]:bg-medusa-bg-subtle-pressed dark:active:[&>code]:bg-medusa-bg-subtle-pressed-dark",
"focus:[&>code]:bg-medusa-bg-subtle-pressed dark:focus:[&>code]:bg-medusa-bg-subtle-pressed-dark",
"hover:[&>code]:bg-medusa-bg-subtle-hover dark:hover:[&>code]:bg-medusa-bg-base-hover-dark"
)}
>
<code
{...props}
className={clsx(
"border-medusa-tag-neutral-border dark:border-medusa-tag-neutral-border-dark border",
"text-medusa-tag-neutral-text dark:text-medusa-tag-neutral-text-dark",
"bg-medusa-tag-neutral-bg dark:bg-medusa-tag-neutral-bg-dark font-monospace text-code-label rounded-sm py-0 px-[6px]",
props.className
)}
/>
</CopyButton>
)}
</>
)
}
export default InlineCode

View File

@@ -1,11 +0,0 @@
import Loading from ".."
const ContentLoading = () => {
return (
<div className="w-api-ref-content">
<Loading />
</div>
)
}
export default ContentLoading

View File

@@ -1,20 +0,0 @@
import IconSpinner from "@/components/Icons/Spinner"
import type IconProps from "@/components/Icons/types"
import clsx from "clsx"
type SpinnerLoadingProps = {
iconProps?: IconProps
}
const SpinnerLoading = ({ iconProps }: SpinnerLoadingProps) => {
return (
<span role="status">
<IconSpinner
{...iconProps}
className={clsx("animate-spin", iconProps?.className)}
/>
</span>
)
}
export default SpinnerLoading

View File

@@ -1,28 +0,0 @@
import clsx from "clsx"
import capitalize from "@/utils/capitalize"
export type MethodLabelProps = {
method: string
className?: string
}
const MethodLabel = ({ method, className }: MethodLabelProps) => {
return (
<span
className={clsx(
"text-compact-x-small-plus rounded-sm border py-0 px-[6px]",
method === "get" &&
"bg-medusa-tag-green-bg dark:bg-medusa-tag-green-bg-dark text-medusa-tag-green-text dark:text-medusa-tag-green-text-dark border-medusa-tag-green-border dark:border-medusa-tag-green-border-dark",
method === "post" &&
"bg-medusa-tag-blue-bg dark:bg-medusa-tag-blue-bg-dark text-medusa-tag-blue-text dark:text-medusa-tag-blue-text-dark border-medusa-tag-blue-border dark:border-medusa-tag-blue-border-dark",
method === "delete" &&
"bg-medusa-tag-red-bg dark:bg-medusa-tag-red-bg-dark text-medusa-tag-red-text dark:text-medusa-tag-red-text-dark border-medusa-tag-red-border dark:border-medusa-tag-red-border-dark",
className
)}
>
{method === "delete" ? "Del" : capitalize(method)}
</span>
)
}
export default MethodLabel

View File

@@ -1,28 +0,0 @@
import clsx from "clsx"
import Button, { ButtonProps } from "../../Button"
type ModalFooterProps = {
actions?: ButtonProps[]
children?: React.ReactNode
className?: string
}
const ModalFooter = ({ actions, children, className }: ModalFooterProps) => {
return (
<div
className={clsx(
"py-1.5 pl-0 pr-2",
"border-medusa-border-base dark:border-medusa-border-base-dark border-0 border-t border-solid",
"flex justify-end gap-0.5",
className
)}
>
{actions?.map((action, index) => (
<Button {...action} key={index} />
))}
{children}
</div>
)
}
export default ModalFooter

View File

@@ -1,38 +0,0 @@
import clsx from "clsx"
import { useModal } from "../../../providers/modal"
import IconXMark from "../../Icons/XMark"
import Button from "../../Button"
type ModalHeaderProps = {
title?: string
}
const ModalHeader = ({ title }: ModalHeaderProps) => {
const { closeModal } = useModal()
return (
<div
className={clsx(
"border-medusa-border-base dark:border-medusa-border-base-dark border-0 border-b border-solid py-1.5 px-2",
"flex items-center justify-between"
)}
>
<span
className={clsx(
"text-medusa-fg-base dark:text-medusa-fg-base-dark text-h2"
)}
>
{title}
</span>
<Button
variant="clear"
className="cursor-pointer"
onClick={() => closeModal()}
>
<IconXMark />
</Button>
</div>
)
}
export default ModalHeader

View File

@@ -1,117 +0,0 @@
import clsx from "clsx"
import React, { forwardRef, useCallback, useEffect, useRef } from "react"
import { ButtonProps } from "../Button"
import { useModal } from "../../providers/modal"
import ModalHeader from "./Header"
import ModalFooter from "./Footer"
import useKeyboardShortcut from "../../hooks/use-keyboard-shortcut"
export type ModalProps = {
className?: string
title?: string
actions?: ButtonProps[]
modalContainerClassName?: string
contentClassName?: string
onClose?: React.ReactEventHandler<HTMLDialogElement>
open?: boolean
footerContent?: React.ReactNode
} & Omit<React.ComponentProps<"dialog">, "ref">
const Modal = forwardRef<HTMLDialogElement, ModalProps>(function Modal(
{
className,
title,
actions,
children,
contentClassName,
modalContainerClassName,
onClose,
open = true,
footerContent,
...props
},
passedRef
) {
const { closeModal } = useModal()
const ref = useRef<HTMLDialogElement | null>(null)
const setRefs = useCallback(
(node: HTMLDialogElement) => {
// Ref's from useRef needs to have the node assigned to `current`
ref.current = node
if (typeof passedRef === "function") {
passedRef(node)
} else if (passedRef && "current" in passedRef) {
passedRef.current = node
}
},
[passedRef]
)
useKeyboardShortcut({
metakey: false,
checkEditing: false,
shortcutKeys: ["escape"],
action: () => {
if (open) {
ref.current?.close()
}
},
})
const handleClick = (e: React.MouseEvent<HTMLDialogElement, MouseEvent>) => {
// close modal when the user clicks outside the content
if (e.target === ref.current) {
closeModal()
onClose?.(e)
}
}
const handleClose = (e: React.SyntheticEvent<HTMLDialogElement, Event>) => {
onClose?.(e)
closeModal()
}
useEffect(() => {
if (open) {
document.body.setAttribute("data-modal", "opened")
} else {
document.body.removeAttribute("data-modal")
}
}, [open])
return (
<dialog
{...props}
className={clsx(
"fixed top-0 left-0 flex h-screen w-screen items-center justify-center",
"bg-medusa-bg-overlay dark:bg-medusa-bg-overlay-dark z-[500]",
"hidden open:flex",
className
)}
onClick={handleClick}
ref={setRefs}
onClose={handleClose}
open={open}
>
<div
className={clsx(
"bg-medusa-bg-base dark:bg-medusa-bg-base-dark rounded-sm",
"border-medusa-border-base dark:border-medusa-border-base-dark border border-solid",
"shadow-modal dark:shadow-modal-dark",
"w-[90%] md:h-auto md:w-[75%] lg:w-[560px]",
modalContainerClassName
)}
>
{title && <ModalHeader title={title} />}
<div className={clsx("overflow-auto py-1.5 px-2", contentClassName)}>
{children}
</div>
{actions && actions?.length > 0 && <ModalFooter actions={actions} />}
{footerContent && <ModalFooter>{footerContent}</ModalFooter>}
</div>
</dialog>
)
})
export default Modal

View File

@@ -1,35 +0,0 @@
"use client"
import { useColorMode } from "@/providers/color-mode"
import NavbarIconButton, { NavbarIconButtonProps } from "../IconButton"
import type IconProps from "@/components/Icons/types"
import dynamic from "next/dynamic"
const IconLightMode = dynamic<IconProps>(
async () => import("../../Icons/LightMode")
) as React.FC<IconProps>
const IconDarkMode = dynamic<IconProps>(
async () => import("../../Icons/DarkMode")
) as React.FC<IconProps>
type NavbarColorModeToggleProps = {
buttonProps?: NavbarIconButtonProps
}
const NavbarColorModeToggle = ({ buttonProps }: NavbarColorModeToggleProps) => {
const { colorMode, toggleColorMode } = useColorMode()
return (
<NavbarIconButton {...buttonProps} onClick={() => toggleColorMode()}>
{colorMode === "light" && (
<IconLightMode iconColorClassName="stroke-medusa-fg-muted dark:stroke-medusa-fg-muted-dark" />
)}
{colorMode === "dark" && (
<IconDarkMode iconColorClassName="stroke-medusa-fg-muted dark:stroke-medusa-fg-muted-dark" />
)}
</NavbarIconButton>
)
}
export default NavbarColorModeToggle

View File

@@ -1,24 +0,0 @@
import clsx from "clsx"
export type NavbarIconButtonProps = React.HTMLAttributes<HTMLButtonElement>
const NavbarIconButton = ({
children,
className,
...props
}: NavbarIconButtonProps) => {
return (
<button
className={clsx(
"btn-secondary btn-secondary-icon",
"[&>svg]:h-[22px] [&>svg]:w-[22px]",
className
)}
{...props}
>
{children}
</button>
)
}
export default NavbarIconButton

View File

@@ -1,42 +0,0 @@
"use client"
import clsx from "clsx"
import Link from "next/link"
import type { LinkProps } from "next/link"
import { useNavbar } from "@/providers/navbar"
import { Area } from "@/types/openapi"
type NavbarLinkProps = {
href: string
label: string
className?: string
activeValue?: Area
} & LinkProps
const NavbarLink = ({
href,
label,
className,
activeValue,
}: NavbarLinkProps) => {
const { activeItem } = useNavbar()
return (
<Link
href={href}
className={clsx(
activeItem === activeValue &&
"text-medusa-fg-base dark:text-medusa-fg-base-dark",
activeItem !== activeValue &&
"text-medusa-fg-subtle dark:text-medusa-fg-subtle-dark",
"text-compact-small-plus inline-block",
"hover:text-medusa-fg-base dark:hover:text-medusa-fg-base-dark",
className
)}
>
{label}
</Link>
)
}
export default NavbarLink

View File

@@ -1,27 +0,0 @@
"use client"
import { useColorMode } from "@/providers/color-mode"
import Image from "next/image"
import Link from "next/link"
const NavbarLogo = () => {
const { colorMode } = useColorMode()
return (
<Link href={`/`} className="flex-1">
<Image
src={
colorMode === "light"
? "/images/logo-icon.png"
: "/images/logo-icon-dark.png"
}
alt="Medusa Logo"
height={20}
width={20}
className="align-middle"
/>
</Link>
)
}
export default NavbarLogo

View File

@@ -1,38 +0,0 @@
"use client"
import NavbarIconButton, { NavbarIconButtonProps } from "../IconButton"
import { useSidebar } from "@/providers/sidebar"
import IconSidebar from "../../Icons/Sidebar"
import clsx from "clsx"
import IconXMark from "../../Icons/XMark"
import { usePageLoading } from "../../../providers/page-loading"
type NavbarMenuButtonProps = {
buttonProps?: NavbarIconButtonProps
}
const NavbarMenuButton = ({ buttonProps }: NavbarMenuButtonProps) => {
const { setMobileSidebarOpen, mobileSidebarOpen } = useSidebar()
const { isLoading } = usePageLoading()
return (
<NavbarIconButton
{...buttonProps}
className={clsx("mr-1 lg:!hidden", buttonProps?.className)}
onClick={() => {
if (!isLoading) {
setMobileSidebarOpen((prevValue) => !prevValue)
}
}}
>
{!mobileSidebarOpen && (
<IconSidebar iconColorClassName="stroke-medusa-fg-muted dark:stroke-medusa-fg-muted-dark" />
)}
{mobileSidebarOpen && (
<IconXMark iconColorClassName="stroke-medusa-fg-muted dark:stroke-medusa-fg-muted-dark" />
)}
</NavbarIconButton>
)
}
export default NavbarMenuButton

View File

@@ -1,27 +0,0 @@
"use client"
import { useColorMode } from "@/providers/color-mode"
import Image from "next/image"
import Link from "next/link"
const NavbarMobileLogo = () => {
const { colorMode } = useColorMode()
return (
<Link href={`/`} className="flex-1 lg:hidden">
<Image
src={
colorMode === "light"
? "/images/logo-mobile.png"
: "/images/logo-mobile-dark.png"
}
alt="Medusa Logo"
height={20}
width={82}
className="mx-auto align-middle"
/>
</Link>
)
}
export default NavbarMobileLogo

View File

@@ -1,38 +0,0 @@
"use client"
import NavbarMenuButton from "../MenuButton"
import NavbarMobileLogo from "../MobileLogo"
import NavbarColorModeToggle from "../ColorModeToggle"
import SearchModalOpener from "../../Search/ModalOpener"
import { useMobile } from "../../../providers/mobile"
const MobileMenu = () => {
const { isMobile } = useMobile()
return (
<div className="flex w-full items-center justify-between lg:hidden">
{isMobile && (
<>
<NavbarMenuButton
buttonProps={{
className:
"!border-none !bg-transparent !bg-no-image !shadow-none",
}}
/>
<NavbarMobileLogo />
<div className="flex">
<SearchModalOpener />
<NavbarColorModeToggle
buttonProps={{
className:
"!border-none !bg-transparent !bg-no-image !shadow-none ml-1",
}}
/>
</div>
</>
)}
</div>
)
}
export default MobileMenu

View File

@@ -1,88 +0,0 @@
"use client"
import IconSidebar from "@/components/Icons/Sidebar"
import Tooltip from "@/components/Tooltip"
import NavbarIconButton from "../IconButton"
import { useSidebar } from "../../../providers/sidebar"
import clsx from "clsx"
import { useEffect, useState } from "react"
const NavbarSidebarButton = () => {
const { desktopSidebarOpen, setDesktopSidebarOpen } = useSidebar()
const [isApple, setIsApple] = useState(false)
const toggleSidebar = () => {
setDesktopSidebarOpen((prevValue) => !prevValue)
}
useEffect(() => {
setIsApple(navigator.userAgent.toLowerCase().indexOf("mac") !== 0)
function isEditingContent(event: KeyboardEvent) {
const element = event.target as HTMLElement
const tagName = element.tagName
return (
element.isContentEditable ||
tagName === "INPUT" ||
tagName === "SELECT" ||
tagName === "TEXTAREA"
)
}
function sidebarShortcut(e: KeyboardEvent) {
if (
(e.metaKey || e.ctrlKey) &&
e.key.toLowerCase() === "i" &&
!isEditingContent(e)
) {
e.preventDefault()
toggleSidebar()
}
}
window.addEventListener("keydown", sidebarShortcut)
return () => {
window.removeEventListener("keydown", sidebarShortcut)
}
}, [])
const getPlatformKey = () =>
`
<kbd class="${clsx(
"bg-medusa-tag-neutral-bg dark:bg-medusa-tag-neutral-bg-dark",
"border border-solid rounded-sm border-medusa-tag-neutral-border dark:border-medusa-tag-neutral-border-dark",
"text-medusa-tag-neutral-text dark:text-medusa-tag-neutral-text font-base text-compact-x-small-plus",
"inline-flex !p-0 justify-center items-center shadow-none ml-0.5",
isApple && "w-[22px] h-[22px]",
!isApple && "w-1.5 h-1.5"
)}">${isApple ? "⌘" : "Ctrl"}</kbd>
`
return (
<Tooltip
html={
desktopSidebarOpen
? `<span class="text-compact-x-small-plus">Close sidebar ${getPlatformKey()}
<kbd class="${clsx(
"bg-medusa-tag-neutral-bg dark:bg-medusa-tag-neutral-bg-dark",
"border border-solid rounded-sm border-medusa-tag-neutral-border dark:border-medusa-tag-neutral-border-dark",
"text-medusa-tag-neutral-text dark:text-medusa-tag-neutral-text font-base text-compact-x-small-plus",
"inline-flex w-[22px] h-[22px] !p-0 justify-center items-center shadow-none"
)}">I</kbd></span>`
: `<span class="text-compact-x-small-plus">Lock sidebar open ${getPlatformKey()}
<kbd class="${clsx(
"bg-medusa-tag-neutral-bg dark:bg-medusa-tag-neutral-bg-dark",
"border border-solid rounded-sm border-medusa-tag-neutral-border dark:border-medusa-tag-neutral-border-dark",
"text-medusa-tag-neutral-text dark:text-medusa-tag-neutral-text font-base text-compact-x-small-plus",
"inline-flex w-[22px] h-[22px] !p-0 justify-center items-center shadow-none"
)}">I</kbd></span>`
}
>
<NavbarIconButton onClick={toggleSidebar}>
<IconSidebar iconColorClassName="stroke-medusa-fg-muted dark:stroke-medusa-fg-muted-dark" />
</NavbarIconButton>
</Tooltip>
)
}
export default NavbarSidebarButton

View File

@@ -1,57 +0,0 @@
import clsx from "clsx"
import NavbarLink from "./Link"
import NavbarColorModeToggle from "./ColorModeToggle"
import NavbarLogo from "./Logo"
import getLinkWithBasePath from "../../utils/get-link-with-base-path"
import FeedbackModal from "./FeedbackModal"
import MobileMenu from "./MobileMenu"
import SearchModalOpener from "../Search/ModalOpener"
const Navbar = () => {
return (
<nav
className={clsx(
"h-navbar sticky top-0 w-full justify-between",
"bg-docs-bg dark:bg-docs-bg-dark border-medusa-border-base dark:border-medusa-border-base-dark z-[400] border-b"
)}
>
<div
className={clsx(
"h-navbar max-w-xxl py-0.75 sticky top-0 mx-auto flex w-full justify-between px-1 lg:px-3"
)}
>
<div className="hidden w-full items-center gap-0.5 lg:flex lg:w-auto lg:gap-1.5">
<NavbarLogo />
<div className="hidden items-center gap-1.5 lg:flex">
<NavbarLink href="https://docs.medusajs.com/" label="Docs" />
<NavbarLink
href="https://docs.medusajs.com/user-guide"
label="User Guide"
/>
<NavbarLink
href={getLinkWithBasePath("/store")}
label="Store API"
activeValue="store"
/>
<NavbarLink
href={getLinkWithBasePath("/admin")}
label="Admin API"
activeValue="admin"
/>
<NavbarLink href="https://docs.medusajs.com/ui" label="UI" />
</div>
</div>
<div className="hidden min-w-0 flex-1 items-center justify-end gap-0.5 lg:flex">
<div>
<SearchModalOpener />
</div>
<NavbarColorModeToggle />
<FeedbackModal />
</div>
<MobileMenu />
</div>
</nav>
)
}
export default Navbar

View File

@@ -1,21 +0,0 @@
import clsx from "clsx"
type SearchHitGroupNameProps = {
name: string
}
const SearchHitGroupName = ({ name }: SearchHitGroupNameProps) => {
return (
<span
className={clsx(
"pb-0.25 flex px-0.5 pt-1",
"text-medusa-fg-muted dark:text-medusa-fg-muted-dark",
"text-compact-x-small-plus"
)}
>
{name}
</span>
)
}
export default SearchHitGroupName

View File

@@ -1,381 +0,0 @@
"use client"
import React, { useCallback, useEffect, useMemo, useRef, useState } from "react"
import algoliasearch, { SearchClient } from "algoliasearch/lite"
import { InstantSearch, SearchBox } from "react-instantsearch"
import Modal from "../../Modal"
import clsx from "clsx"
import IconMagnifyingGlass from "../../Icons/MagnifyingGlass"
import IconXMark from "../../Icons/XMark"
import SearchEmptyQueryBoundary from "../EmptyQueryBoundary"
import SearchSuggestions from "../Suggestions"
import { useSearch } from "../../../providers/search"
import checkArraySameElms from "../../../utils/array-same-elms"
import SearchHitsWrapper from "../Hits"
import Button from "../../Button"
import Kbd from "../../MDXComponents/Kbd"
import { OptionType } from "../../../hooks/use-select"
import SelectBadge from "../../Select/Badge"
import useKeyboardShortcut from "../../../hooks/use-keyboard-shortcut"
import { findNextSibling, findPrevSibling } from "../../../utils/dom-utils"
const algoliaClient = algoliasearch(
process.env.NEXT_PUBLIC_ALGOLIA_APP_ID || "temp",
process.env.NEXT_PUBLIC_ALGOLIA_API_KEY || "temp"
)
const searchClient: SearchClient = {
...algoliaClient,
async search(requests) {
if (requests.every(({ params }) => !params?.query)) {
return Promise.resolve({
results: requests.map(() => ({
hits: [],
nbHits: 0,
nbPages: 0,
page: 0,
processingTimeMS: 0,
hitsPerPage: 0,
exhaustiveNbHits: false,
query: "",
params: "",
})),
})
}
return algoliaClient.search(requests)
},
}
const SearchModal = () => {
const modalRef = useRef<HTMLDialogElement | null>(null)
const options: OptionType[] = useMemo(() => {
return [
{
value: "admin",
label: "Admin API",
},
{
value: "store",
label: "Store API",
},
{
value: "docs",
label: "Docs",
},
{
value: "user-guide",
label: "User Guide",
},
{
value: "plugins",
label: "Plugins",
},
{
value: "reference",
label: "References",
},
{
value: "ui",
label: "UI",
},
]
}, [])
const { isOpen, setIsOpen, defaultFilters } = useSearch()
const [filters, setFilters] = useState<string[]>(defaultFilters)
const formattedFilters: string = useMemo(() => {
let formatted = ""
filters.forEach((filter) => {
const split = filter.split("_")
split.forEach((f) => {
if (formatted.length) {
formatted += " OR "
}
formatted += `_tags:${f}`
})
})
return formatted
}, [filters])
const searchBoxRef = useRef<HTMLFormElement>(null)
const focusSearchInput = () =>
searchBoxRef.current?.querySelector("input")?.focus()
useEffect(() => {
if (!checkArraySameElms(defaultFilters, filters)) {
setFilters(defaultFilters)
}
}, [defaultFilters])
useEffect(() => {
if (isOpen && searchBoxRef.current) {
focusSearchInput()
} else if (!isOpen) {
const focusedItem = modalRef.current?.querySelector(
":focus"
) as HTMLElement
if (
focusedItem &&
focusedItem === searchBoxRef.current?.querySelector("input")
) {
// remove focus
focusedItem.blur()
}
}
}, [isOpen])
const handleKeyAction = (e: KeyboardEvent) => {
if (!isOpen) {
return
}
e.preventDefault()
const focusedItem = modalRef.current?.querySelector(":focus") as HTMLElement
if (!focusedItem) {
// focus the first data-hit
const nextItem = modalRef.current?.querySelector(
"[data-hit]"
) as HTMLElement
nextItem?.focus()
return
}
const isHit = focusedItem.hasAttribute("data-hit")
const isInput = focusedItem.tagName.toLowerCase() === "input"
if (!isHit && !isInput) {
// ignore if focused items aren't input/data-hit
return
}
const lowerPressedKey = e.key.toLowerCase()
if (lowerPressedKey === "enter") {
if (isHit) {
// trigger click event of the focused element
focusedItem.click()
}
return
}
if (lowerPressedKey === "arrowup") {
// only hit items has action on arrow up
if (isHit) {
// find if there's a data-hit item before this one
const beforeItem = findPrevSibling(focusedItem, "[data-hit]")
if (!beforeItem) {
// focus the input
focusSearchInput()
} else {
// focus the previous item
beforeItem.focus()
}
}
} else if (lowerPressedKey === "arrowdown") {
// check if item is input or hit
if (isInput) {
// go to the first data-hit item
const nextItem = modalRef.current?.querySelector(
"[data-hit]"
) as HTMLElement
nextItem?.focus()
} else {
// handle go down for hit items
// find if there's a data-hit item after this one
const afterItem = findNextSibling(focusedItem, "[data-hit]")
if (afterItem) {
// focus the next item
afterItem.focus()
}
}
}
}
const shortcutKeys = useMemo(() => ["ArrowUp", "ArrowDown", "Enter"], [])
useKeyboardShortcut({
metakey: false,
shortcutKeys,
action: handleKeyAction,
checkEditing: false,
preventDefault: false,
})
const handleKeyDown = useCallback(
(e: KeyboardEvent) => {
if (!isOpen) {
return
}
// check if shortcut keys were pressed
const lowerPressedKey = e.key.toLowerCase()
const pressedShortcut = [...shortcutKeys, "Escape"].some(
(s) => s.toLowerCase() === lowerPressedKey
)
if (pressedShortcut) {
return
}
const focusedItem = modalRef.current?.querySelector(
":focus"
) as HTMLElement
const searchInput = searchBoxRef.current?.querySelector(
"input"
) as HTMLInputElement
if (searchInput && focusedItem !== searchInput) {
searchInput.focus()
}
},
[shortcutKeys, isOpen]
)
useEffect(() => {
window.addEventListener("keydown", handleKeyDown)
return () => {
window.removeEventListener("keydown", handleKeyDown)
}
}, [handleKeyDown])
return (
<Modal
contentClassName={clsx(
"!p-0 overflow-hidden relative h-full",
"rounded-none md:rounded-lg flex flex-col justify-between"
)}
modalContainerClassName="w-screen h-screen !rounded-none md:!rounded-lg"
open={isOpen}
onClose={() => setIsOpen(false)}
ref={modalRef}
>
<InstantSearch
indexName={process.env.NEXT_PUBLIC_API_ALGOLIA_INDEX_NAME}
searchClient={searchClient}
>
<div
className={clsx("bg-medusa-bg-base dark:bg-medusa-bg-base-dark flex")}
>
<SearchBox
classNames={{
root: clsx(
"h-[56px] w-full md:rounded-t-xl relative border-b border-medusa-border-base dark:border-medusa-border-base-dark",
"bg-transparent"
),
form: clsx("h-full md:rounded-t-xl bg-transparent"),
input: clsx(
"w-full h-full pl-3 text-medusa-fg-base dark:text-medusa-fg-base-dark",
"placeholder:text-medusa-fg-muted dark:placeholder:text-medusa-fg-muted-dark",
"md:rounded-t-xl text-compact-medium bg-transparent",
"appearance-none search-cancel:hidden active:outline-none focus:outline-none"
),
submit: clsx("absolute top-[18px] left-1"),
reset: clsx(
"absolute top-0.75 right-1 hover:bg-medusa-bg-base-hover dark:hover:bg-medusa-bg-base-hover-dark",
"p-[5px] md:rounded"
),
loadingIndicator: clsx("absolute top-[18px] right-1"),
}}
submitIconComponent={() => (
<IconMagnifyingGlass iconColorClassName="stroke-medusa-fg-muted dark:stroke-medusa-fg-muted-dark" />
)}
resetIconComponent={() => (
<IconXMark
iconColorClassName="stroke-medusa-fg-subtle dark:stroke-medusa-fg-subtle-dark"
className="hidden md:block"
/>
)}
placeholder="Find something..."
autoFocus
formRef={searchBoxRef}
/>
<Button
variant="clear"
className={clsx(
"bg-medusa-bg-base dark:bg-medusa-bg-base-dark block md:hidden",
"border-medusa-border-base dark:border-medusa-border-base-dark border-b",
"pr-1"
)}
onClick={() => setIsOpen(false)}
>
<IconXMark iconColorClassName="stroke-medusa-fg-muted dark:stroke-medusa-fg-muted-dark" />
</Button>
</div>
<div className="mx-0.5 h-[calc(100%-120px)] md:h-[332px] md:flex-initial lg:max-h-[332px] lg:min-h-[332px]">
<SearchEmptyQueryBoundary fallback={<SearchSuggestions />}>
<SearchHitsWrapper
configureProps={{
filters: formattedFilters,
attributesToSnippet: [
"content",
"hierarchy.lvl1",
"hierarchy.lvl2",
],
attributesToHighlight: [
"content",
"hierarchy.lvl1",
"hierarchy.lvl2",
],
}}
/>
</SearchEmptyQueryBoundary>
</div>
</InstantSearch>
<div
className={clsx(
"py-0.75 flex items-center justify-between px-1",
"border-medusa-border-base dark:border-medusa-border-base-dark border-t",
"bg-medusa-bg-base dark:bg-medusa-bg-base-dark"
)}
>
<SelectBadge
multiple
options={options}
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(options.map((option) => option.value))
}
}}
/>
<div className="hidden items-center gap-1 md:flex">
<div className="flex items-center gap-0.5">
<span
className={clsx(
"text-medusa-fg-subtle dark:text-medusa-fg-subtle-dark",
"text-compact-x-small"
)}
>
Navigation
</span>
<span className="gap-0.25 flex">
<Kbd></Kbd>
<Kbd></Kbd>
</span>
</div>
<div className="flex items-center gap-0.5">
<span
className={clsx(
"text-medusa-fg-subtle dark:text-medusa-fg-subtle-dark",
"text-compact-x-small"
)}
>
Open Result
</span>
<Kbd></Kbd>
</div>
</div>
</div>
</Modal>
)
}
export default SearchModal

View File

@@ -1,14 +0,0 @@
import IconExclamationCircleSolid from "../../Icons/ExclamationCircleSolid"
const SearchNoResult = () => {
return (
<div className="flex h-full w-full flex-col items-center justify-center gap-1">
<IconExclamationCircleSolid iconColorClassName="fill-medusa-fg-muted dark:fill-medusa-fg-muted-dark" />
<span className="text-compact-small text-medusa-fg-muted dark:text-medusa-fg-muted-dark">
No results found. Try changing selected filters.
</span>
</div>
)
}
export default SearchNoResult

View File

@@ -1,49 +0,0 @@
import clsx from "clsx"
import { useInstantSearch } from "react-instantsearch"
import SearchHitGroupName from "../Hits/GroupName"
const SearchSuggestions = () => {
const { setIndexUiState } = useInstantSearch()
const suggestions = [
"Authentication",
"Expanding fields",
"Selecting fields",
"Pagination",
"Query parameter types",
]
return (
<div className="h-full overflow-auto">
<SearchHitGroupName name={"Search suggestions"} />
{suggestions.map((suggestion, index) => (
<div
className={clsx(
"flex items-center justify-between",
"cursor-pointer rounded-sm p-0.5",
"hover:bg-medusa-bg-base-hover dark:hover:bg-medusa-bg-base-hover-dark",
"focus:bg-medusa-bg-base-hover dark:focus:bg-medusa-bg-base-hover-dark",
"last:mb-1 focus:outline-none"
)}
onClick={() =>
setIndexUiState({
query: suggestion,
})
}
key={index}
tabIndex={index}
data-hit
>
<span
className={clsx(
"text-medusa-fg-base dark:text-medusa-fg-base-dark",
"text-compact-small"
)}
>
{suggestion}
</span>
</div>
))}
</div>
)
}
export default SearchSuggestions

View File

@@ -1,135 +0,0 @@
import { useCallback, useRef, useState } from "react"
import useSelect from "../../../hooks/use-select"
import clsx from "clsx"
import SelectDropdown from "../Dropdown"
import { SelectProps } from "../types"
const SelectBadge = ({
value,
options,
setSelected,
addSelected,
removeSelected,
multiple,
className,
addAll = multiple,
handleAddAll,
...props
}: SelectProps) => {
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 getSelectedText = useCallback(() => {
let str = ""
const selectedOptions = options.filter((option) =>
value.includes(option.value)
)
if (isAllSelected) {
str = "All Areas"
} else {
if (
(!Array.isArray(value) && !value) ||
(Array.isArray(value) && !value.length)
) {
str = "None selected"
} else {
str = selectedOptions[0].label
}
}
return (
<>
<span
className={clsx(
"text-medusa-fg-base dark:text-medusa-fg-base-dark",
"text-compact-x-small-plus",
"inline-block w-[60px] max-w-[60px] overflow-hidden text-ellipsis"
)}
>
{str}
</span>
{!isAllSelected && selectedOptions.length > 1 && (
<span
className={clsx(
"text-medusa-fg-subtle dark:text-medusa-fg-subtle-dark",
"text-compact-x-small"
)}
>
{" "}
+ {selectedOptions.length}
</span>
)}
</>
)
}, [isAllSelected, options, value])
return (
<div className={clsx("relative", className)}>
<div
className={clsx(
"border-medusa-border-base dark:border-medusa-border-base-dark rounded-sm border",
"hover:bg-medusa-bg-subtle-hover dark:hover:bg-medusa-bg-subtle-hover-dark",
"py-0.25 h-fit cursor-pointer px-0.5",
"flex items-center gap-[6px] whitespace-nowrap",
"text-medusa-fg-subtle dark:text-medusa-fg-subtle-dark",
!open && "bg-medusa-bg-subtle dark:bg-medusa-bg-subtle-dark",
open &&
"bg-medusa-bg-subtle-hover dark:bg-medusa-bg-subtle-hover-dark",
className
)}
ref={ref}
onClick={(e) => {
if (!dropdownRef.current?.contains(e.target as Element)) {
setOpen((prev) => !prev)
}
}}
>
<span
className={clsx(
"text-medusa-fg-subtle dark:text-medusa-fg-subtle-dark",
"text-compact-x-small"
)}
>
Show results from:{" "}
</span>
{getSelectedText()}
</div>
<input
type="hidden"
name={props.name}
value={Array.isArray(value) ? value.join(",") : value}
/>
<SelectDropdown
options={options}
open={open}
setOpen={setOpen}
addAll={addAll}
multiple={multiple}
isAllSelected={isAllSelected}
isValueSelected={isValueSelected}
handleSelectAll={handleSelectAll}
handleChange={handleChange}
parentRef={ref}
ref={dropdownRef}
className={clsx(
"!top-[unset] !bottom-full",
open && "!-translate-y-0.5"
)}
/>
</div>
)
}
export default SelectBadge

View File

@@ -1,151 +0,0 @@
import clsx from "clsx"
import IconCheckMini from "../../Icons/CheckMini"
import IconEllipseMiniSolid from "../../Icons/EllipseMiniSolid"
import { OptionType } from "../../../hooks/use-select"
import { forwardRef, useCallback, useEffect, useRef } from "react"
type SelectDropdownProps = {
options: OptionType[]
open: boolean
setOpen: React.Dispatch<React.SetStateAction<boolean>>
addAll?: boolean
multiple?: boolean
isAllSelected: boolean
isValueSelected: (val: string) => boolean
handleSelectAll: () => void
handleChange?: (selectedValue: string, wasSelected: boolean) => void
parentRef?: React.RefObject<HTMLDivElement>
className?: string
}
const SelectDropdown = forwardRef<HTMLDivElement, SelectDropdownProps>(
function SelectDropdown(
{
open,
setOpen,
options,
addAll,
multiple = false,
isAllSelected,
isValueSelected,
handleSelectAll,
handleChange: handleSelectChange,
parentRef,
className,
},
passedRef
) {
const ref = useRef<HTMLDivElement | null>(null)
const setRefs = useCallback(
(node: HTMLDivElement) => {
// Ref's from useRef needs to have the node assigned to `current`
ref.current = node
if (typeof passedRef === "function") {
passedRef(node)
} else if (passedRef && "current" in passedRef) {
passedRef.current = node
}
},
[passedRef]
)
const handleChange = (clickedValue: string, wasSelected: boolean) => {
handleSelectChange?.(clickedValue, wasSelected)
if (!multiple) {
setOpen(false)
}
}
const handleOutsideClick = useCallback(
(e: MouseEvent) => {
if (
open &&
!ref.current?.contains(e.target as Element) &&
!parentRef?.current?.contains(e.target as Element)
) {
setOpen(false)
}
},
[open, parentRef, setOpen]
)
useEffect(() => {
document.body.addEventListener("click", handleOutsideClick)
return () => {
document.body.removeEventListener("click", handleOutsideClick)
}
}, [handleOutsideClick])
const getSelectOption = (option: OptionType, index: number) => {
const isSelected = option.isAllOption
? isAllSelected
: isValueSelected(option.value)
return (
<li
key={index}
className={clsx(
"pr-0.75 relative rounded-sm py-0.5 pl-2.5",
"hover:bg-medusa-bg-base-hover dark:hover:bg-medusa-bg-base-hover-dark",
"[&>svg]:left-0.75 cursor-pointer [&>svg]:absolute [&>svg]:top-0.5",
!isSelected && "text-compact-small",
isSelected && "text-compact-small-plus"
)}
onClick={() => {
if (option.isAllOption) {
handleSelectAll()
} else {
handleChange(option.value, isSelected)
}
}}
>
{isSelected && (
<>
{multiple && (
<IconCheckMini className="stroke-medusa-fg-base dark:stroke-medusa-fg-base-dark" />
)}
{!multiple && (
<IconEllipseMiniSolid className="fill-medusa-fg-base dark:fill-medusa-fg-base-dark" />
)}
</>
)}
{option.label}
</li>
)
}
return (
<div
className={clsx(
"absolute top-full left-0 w-full",
"z-10 h-0 translate-y-0 overflow-hidden transition-transform",
open && "h-auto translate-y-0.5 !overflow-visible",
className
)}
ref={setRefs}
>
<ul
className={clsx(
"p-0.25 mb-0 w-full overflow-auto rounded",
"bg-medusa-bg-base dark:bg-medusa-bg-base-dark text-medusa-fg-base dark:text-medusa-fg-base-dark",
"shadow-flyout dark:shadow-flyout-dark list-none"
)}
>
{addAll &&
getSelectOption(
{
value: "all",
label: "All Areas",
isAllOption: true,
},
-1
)}
{options.map(getSelectOption)}
</ul>
</div>
)
}
)
export default SelectDropdown

View File

@@ -1,106 +0,0 @@
import type { SidebarItemType } from "@/providers/sidebar"
import { useSidebar } from "@/providers/sidebar"
import clsx from "clsx"
import dynamic from "next/dynamic"
import Link from "next/link"
import { useEffect, useMemo, useRef, useState } from "react"
import type { MethodLabelProps } from "../../MethodLabel"
import checkSidebarItemVisibility from "@/utils/check-sidebar-item-visibility"
import Loading from "../../Loading"
const MethodLabel = dynamic<MethodLabelProps>(
async () => import("../../MethodLabel")
) as React.FC<MethodLabelProps>
export type SidebarItemProps = {
item: SidebarItemType
nested?: boolean
} & React.AllHTMLAttributes<HTMLLIElement>
const SidebarItem = ({ item, nested = false, className }: SidebarItemProps) => {
const [showLoading, setShowLoading] = useState(false)
const { isItemActive, setMobileSidebarOpen: setSidebarOpen } = useSidebar()
const active = useMemo(() => {
return isItemActive(item, nested)
}, [isItemActive, item, nested])
const collapsed = !isItemActive(item, true)
const ref = useRef<HTMLLIElement>(null)
useEffect(() => {
if (active && ref.current && window.innerWidth >= 1025) {
if (
!checkSidebarItemVisibility(ref.current, {
topMargin: 57,
})
) {
// scroll to element
ref.current.scrollIntoView({
block: "center",
})
}
}
if (active) {
setShowLoading(true)
}
}, [active])
return (
<li
className={clsx(
item.hasChildren && !collapsed && "my-1.5",
!item.hasChildren && !nested && active && "mt-1.5",
((item.hasChildren && !collapsed) ||
(!item.hasChildren && !nested && active)) &&
"-translate-y-1 transition-transform",
className
)}
ref={ref}
>
<Link
href={item.isPathHref ? item.path : `#${item.path}`}
className={clsx(
"flex items-center justify-between gap-0.5 rounded-sm border px-0.5 py-[6px] hover:no-underline",
!item.hasChildren &&
"text-compact-small-plus text-medusa-fg-subtle dark:text-medusa-fg-subtle-dark",
item.hasChildren &&
"text-compact-x-small-plus text-medusa-fg-muted dark:text-medusa-fg-muted-dark uppercase",
active &&
"!text-medusa-fg-base dark:!text-medusa-fg-base-dark bg-medusa-bg-base-pressed dark:bg-medusa-bg-base-pressed-dark",
active &&
"border-medusa-border-base dark:border-medusa-border-base-dark",
!active &&
"hover:bg-medusa-bg-base-hover dark:hover:bg-medusa-bg-base-hover-dark border-transparent"
)}
scroll={true}
onClick={() => {
if (window.innerWidth < 1025) {
setSidebarOpen(false)
}
}}
replace
shallow
>
<span>{item.title}</span>
{item.method && <MethodLabel method={item.method} className="h-fit" />}
</Link>
{item.hasChildren && (
<ul
className={clsx("ease-ease overflow-hidden", collapsed && "m-0 h-0")}
>
{showLoading && !item.loaded && (
<Loading
count={3}
className="!mb-0 !px-0.5"
barClassName="h-[20px]"
/>
)}
{item.children?.map((childItem, index) => (
<SidebarItem item={childItem} key={index} nested={true} />
))}
</ul>
)}
</li>
)
}
export default SidebarItem

View File

@@ -1,289 +0,0 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
h1 {
@apply text-h1 mb-1;
}
h2 {
@apply text-h2 mb-1;
}
h3 {
@apply text-h3 mb-0.5;
}
h4 {
@apply text-h4 mb-0.5;
}
h1, h2, h3, h4 {
@apply text-medusa-fg-base dark:text-medusa-fg-base-dark;
}
hr {
@apply h-[1px] w-full border-0 bg-medusa-border-base dark:bg-medusa-border-base-dark my-2;
}
p, ul, ol {
@apply mb-1.5;
}
html {
-webkit-font-smoothing: antialiased;
}
body {
@apply overflow-x-hidden;
}
*::selection {
@apply bg-medusa-bg-highlight dark:bg-medusa-bg-highlight-dark;
}
pre *::selection {
@apply !bg-medusa-code-text-highlight;
}
body[data-modal="opened"] {
@apply !overflow-hidden;
}
mark {
@apply bg-medusa-bg-highlight dark:bg-medusa-bg-highlight-dark;
@apply text-medusa-fg-interactive dark:text-medusa-fg-interactive-dark;
}
}
@layer utilities {
@-webkit-keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@-webkit-keyframes fadeOut {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
@keyframes fadeOut {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
@keyframes bounceIn {
from,
20%,
40%,
60%,
80%,
to {
animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
}
0% {
opacity: 0;
transform: scale3d(0.3, 0.3, 0.3);
}
20% {
transform: scale3d(1.1, 1.1, 1.1);
}
40% {
transform: scale3d(0.9, 0.9, 0.9);
}
60% {
opacity: 1;
transform: scale3d(1.03, 1.03, 1.03);
}
80% {
transform: scale3d(0.97, 0.97, 0.97);
}
to {
opacity: 1;
transform: scale3d(1, 1, 1);
}
}
@-webkit-keyframes bounceIn {
from,
20%,
40%,
60%,
80%,
to {
animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
}
0% {
opacity: 0;
transform: scale3d(0.3, 0.3, 0.3);
}
20% {
transform: scale3d(1.1, 1.1, 1.1);
}
40% {
transform: scale3d(0.9, 0.9, 0.9);
}
60% {
opacity: 1;
transform: scale3d(1.03, 1.03, 1.03);
}
80% {
transform: scale3d(0.97, 0.97, 0.97);
}
to {
opacity: 1;
transform: scale3d(1, 1, 1);
}
}
@keyframes bounceOut {
20% {
transform: scale3d(0.9, 0.9, 0.9);
}
50%,
55% {
opacity: 1;
transform: scale3d(1.1, 1.1, 1.1);
}
to {
opacity: 0;
transform: scale3d(0.3, 0.3, 0.3);
}
}
@-webkit-keyframes bounceOut {
20% {
transform: scale3d(0.9, 0.9, 0.9);
}
50%,
55% {
opacity: 1;
transform: scale3d(1.1, 1.1, 1.1);
}
to {
opacity: 0;
transform: scale3d(0.3, 0.3, 0.3);
}
}
.animate-fadeIn {
animation: fadeIn 500ms;
}
.animate-fadeOut {
animation: fadeOut 300ms;
}
.animate-bounceIn {
animation: bounceIn 300ms;
}
.animate-bounceOut {
animation: bounceOut 300ms;
}
.animate-fill-forwards {
animation-fill-mode: forwards;
}
.animate-fast {
animation-duration: 300ms;
}
.clip {
clip-path: inset(0);
}
.no-marker {
@apply marker:content-none;
}
.no-marker::-webkit-details-marker {
@apply hidden;
}
}
@layer components {
.btn-secondary {
@apply inline-flex flex-row justify-center items-center;
@apply py-[5px] px-0.75 rounded-sm cursor-pointer;
@apply bg-button-neutral bg-medusa-button-neutral dark:bg-button-neutral-dark dark:bg-medusa-button-neutral-dark;
@apply hover:bg-medusa-button-neutral-hover hover:bg-no-image dark:hover:bg-medusa-button-neutral-hover-dark hover:no-underline;
@apply active:bg-medusa-button-neutral-pressed active:bg-no-image dark:active:bg-medusa-button-neutral-pressed-dark;
@apply focus:bg-medusa-button-neutral-pressed focus:bg-no-image dark:focus:bg-medusa-button-neutral-pressed-dark;
@apply disabled:!bg-no-image disabled:bg-medusa-bg-disabled dark:disabled:bg-medusa-bg-disabled-dark;
@apply disabled:cursor-not-allowed;
@apply border border-solid border-medusa-border-base dark:border-medusa-border-base-dark;
@apply text-compact-small-plus text-medusa-fg-base dark:text-medusa-fg-base-dark;
@apply shadow-button-neutral focus:shadow-button-neutral-focused active:shadow-button-neutral-focused transition-shadow;
@apply dark:shadow-button-neutral dark:focus:shadow-button-neutral-focused dark:active:shadow-button-neutral-focused;
@apply select-none;
}
.btn-secondary-icon {
@apply !p-0.25;
}
.btn-primary {
@apply inline-flex flex-row justify-center items-center;
@apply py-[5px] px-0.75 rounded-sm cursor-pointer;
@apply bg-button-inverted bg-medusa-button-inverted dark:bg-button-inverted-dark dark:bg-medusa-button-inverted-dark;
@apply hover:bg-medusa-button-inverted-hover hover:bg-no-image dark:hover:bg-medusa-button-inverted-hover-dark hover:no-underline;
@apply active:bg-medusa-button-inverted-pressed active:bg-no-image dark:active:bg-medusa-button-inverted-pressed-dark;
@apply focus:bg-medusa-button-inverted-pressed focus:bg-no-image dark:focus:bg-medusa-button-inverted-pressed-dark;
@apply shadow-button-colored active:shadow-button-colored-focused focus:shadow-button-colored-focused transition-shadow;
@apply dark:shadow-button-colored-dark dark:active:shadow-button-colored-focused-dark dark:focus:shadow-button-colored-focused-dark;
@apply disabled:!bg-no-image disabled:bg-medusa-bg-disabled dark:disabled:bg-medusa-bg-disabled-dark;
@apply disabled:cursor-not-allowed disabled:border-medusa-border-base dark:disabled:border-medusa-border-base-dark;
@apply text-compact-small-plus text-medusa-fg-on-inverted dark:text-medusa-fg-on-inverted-dark;
@apply disabled:text-medusa-fg-disabled dark:disabled:text-medusa-fg-disabled-dark;
@apply border border-medusa-border-loud dark:border-medusa-border-loud-dark;
@apply select-none;
}
.btn-clear {
@apply bg-transparent shadow-none border-0 outline-none cursor-pointer;
}
}
@import url('./tooltip.css');

View File

@@ -1,10 +0,0 @@
:root {
--rt-opacity: theme(opacity.100) !important;
--rt-color-dark: theme(colors.medusa.bg.base.DEFAULT) !important;
--rt-color-white: theme(colors.medusa.fg.subtle.DEFAULT) !important;
}
[data-theme="dark"] {
--rt-color-dark: theme(colors.medusa.bg.base.dark) !important;
--rt-color-white: theme(colors.medusa.fg.subtle.dark) !important;
}

View File

@@ -1,70 +0,0 @@
"use client"
import { createContext, useContext, useEffect, useState } from "react"
type ControlledHeightContextType = {
height: number
}
const ControlledHeightContext =
createContext<ControlledHeightContextType | null>(null)
type ControlledHeightProvider = {
children?: React.ReactNode
}
const ControlledHeightProvider = ({ children }: ControlledHeightProvider) => {
const [height, setHeight] = useState(0)
const initHeight = () => {
const storedHeight = window.localStorage.getItem("height")
if (storedHeight) {
setHeight(parseFloat(storedHeight))
}
const resizeObserver = new ResizeObserver((entries) => {
window.localStorage.setItem(
"height",
`${entries[0].contentBoxSize[0].inlineSize}`
)
setHeight(entries[0].target.clientHeight)
})
resizeObserver.observe(document.body)
}
useEffect(() => {
if (height !== document.body.clientHeight) {
document.body.style.height = `${height}px`
}
}, [height])
useEffect(() => {
initHeight()
}, [])
return (
<ControlledHeightContext.Provider
value={{
height,
}}
>
{children}
</ControlledHeightContext.Provider>
)
}
export default ControlledHeightProvider
export const useControlledHeight = (): ControlledHeightContextType => {
const context = useContext(ControlledHeightContext)
if (!context) {
throw new Error(
"useControlledHeight must be used inside an ControlledHeightProvider"
)
}
return context
}

View File

@@ -1,42 +0,0 @@
"use client"
import type { Area } from "@/types/openapi"
import { createContext, useContext, useState } from "react"
type NavbarContextType = {
activeItem: Area | null
setActiveItem: (value: Area) => void
}
const NavbarContext = createContext<NavbarContextType | null>(null)
type NavbarProviderProps = {
children: React.ReactNode
}
const NavbarProvider = ({ children }: NavbarProviderProps) => {
const [activeItem, setActiveItem] = useState<Area | null>(null)
return (
<NavbarContext.Provider
value={{
activeItem,
setActiveItem,
}}
>
{children}
</NavbarContext.Provider>
)
}
export default NavbarProvider
export const useNavbar = (): NavbarContextType => {
const context = useContext(NavbarContext)
if (!context) {
throw new Error("useNavbar must be used inside a NavbarProvider")
}
return context
}

View File

@@ -1,48 +0,0 @@
"use client"
import { createContext, useContext, useState } from "react"
import SearchModal from "../components/Search/Modal"
type SearchContextType = {
isOpen: boolean
setIsOpen: React.Dispatch<React.SetStateAction<boolean>>
defaultFilters: string[]
setDefaultFilters: (value: string[]) => void
}
const SearchContext = createContext<SearchContextType | null>(null)
type SearchProviderProps = {
children: React.ReactNode
}
const SearchProvider = ({ children }: SearchProviderProps) => {
const [isOpen, setIsOpen] = useState(false)
const [defaultFilters, setDefaultFilters] = useState<string[]>([])
return (
<SearchContext.Provider
value={{
isOpen,
setIsOpen,
defaultFilters,
setDefaultFilters,
}}
>
{children}
<SearchModal />
</SearchContext.Provider>
)
}
export default SearchProvider
export const useSearch = (): SearchContextType => {
const context = useContext(SearchContext)
if (!context) {
throw new Error("useSearch must be used inside a SearchProvider")
}
return context
}

View File

@@ -1,10 +0,0 @@
export default function checkArraySameElms(
arr1: Array<any>,
arr2: Array<any>
): boolean {
if (arr1.length !== arr2.length) {
return false
}
return arr1.every((value, index) => value === arr2[index])
}

View File

@@ -1,6 +0,0 @@
{
"crons": [{
"path": "/api/algolia",
"schedule": "0 0 * * 4"
}]
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,11 @@
module.exports = {
root: true,
extends: [
"docs/next"
],
settings: {
next: {
rootDir: ".",
},
},
}

View File

@@ -37,4 +37,7 @@ next-env.d.ts
# unnecessary specs
specs/admin.oas.json
specs/store.oas.json
specs/store.oas.json
# analyzer
analyze

View File

@@ -0,0 +1 @@
nmMode: hardlinks-local

View File

@@ -1,6 +1,6 @@
import CodeTabs from "@/components/CodeTabs"
import Feedback from "@/components/Feedback"
import { Feedback, CodeTabs } from "docs-ui"
import SectionContainer from "@/components/Section/Container"
import formatReportLink from "@/utils/format-report-link"
<SectionContainer noTopPadding={true}>
@@ -22,7 +22,8 @@ Aside from this API reference, check out the [Commerce Modules](https://docs.med
area: "admin",
section: "introduction"
}}
sectionTitle="Introduction"
reportLink={formatReportLink("admin", "Introduction")}
pathName="/api/admin"
/>
</SectionContainer>
@@ -148,8 +149,9 @@ You can also pass it to client libraries:
area: "admin",
section: "authentication-api-key"
}}
sectionTitle="Authentication - API Token"
className="mb-3"
reportLink={formatReportLink("admin", "Authentication - API Token")}
pathName="/api/admin"
/>
### Cookie Session ID
@@ -219,7 +221,8 @@ fetch(`<BACKEND_URL>/admin/products`, {
area: "admin",
section: "authentication-cookie"
}}
sectionTitle="Authentication - Cookie Session ID"
reportLink={formatReportLink("admin", "Authentication - Cookie Session ID")}
pathName="/api/admin"
/>
</SectionContainer>
@@ -290,7 +293,8 @@ const App = () => {
area: "admin",
section: "http-compression"
}}
sectionTitle="HTTP Compression"
reportLink={formatReportLink("admin", "Authentication - Cookie Session ID")}
pathName="/api/admin"
/>
</SectionContainer>
@@ -501,7 +505,8 @@ relations like `collection`.
area: "admin",
section: "expand"
}}
sectionTitle="Expanding Fields"
reportLink={formatReportLink("admin", "Expanding Fields")}
pathName="/api/admin"
/>
</SectionContainer>
@@ -831,7 +836,8 @@ export default Products`,
area: "admin",
section: "select-fields"
}}
sectionTitle="Selecting Fields"
reportLink={formatReportLink("admin", "Selecting Fields")}
pathName="/api/admin"
/>
</SectionContainer>
@@ -981,7 +987,8 @@ curl -g "http://localhost:9000/admin/products?created_at[lt]=2023-02-17&created_
area: "admin",
section: "query-parameters"
}}
sectionTitle="Query Parameter Types"
reportLink={formatReportLink("admin", "Query Parameter Types")}
pathName="/api/admin"
/>
</SectionContainer>
@@ -1204,7 +1211,8 @@ order.
area: "admin",
section: "pagination"
}}
sectionTitle="Pagination"
reportLink={formatReportLink("admin", "Pagination")}
pathName="/api/admin"
/>
</SectionContainer>

View File

@@ -1,4 +1,4 @@
import CodeTabs from "@/components/CodeTabs"
import { CodeTabs } from "docs-ui"
import Space from "@/components/Space"
### Just Getting Started?

View File

@@ -1,6 +1,7 @@
import Feedback from "@/components/Feedback"
import CodeTabs from "@/components/CodeTabs"
import { Feedback, CodeTabs } from "docs-ui"
import SectionContainer from "@/components/Section/Container"
import formatReportLink from "@/utils/format-report-link"
<SectionContainer noTopPadding={true}>
@@ -22,7 +23,8 @@ Aside from this API reference, check out the [Commerce Modules](https://docs.med
area: "store",
section: "introduction"
}}
sectionTitle="Introduction"
reportLink={formatReportLink("store", "Introduction")}
pathName="/api/store"
/>
</SectionContainer>
@@ -99,7 +101,8 @@ fetch(`<BACKEND_URL>/admin/products`, {
area: "store",
section: "authentication-cookie"
}}
sectionTitle="Authentication - Cookie Session ID"
reportLink={formatReportLink("store", "Authentication - Cookie Session ID")}
pathName="/api/store"
/>
</SectionContainer>
@@ -182,7 +185,8 @@ const App = () => {
area: "store",
section: "publishable-api-key"
}}
sectionTitle="Publishable API Key"
reportLink={formatReportLink("store", "Publishable API Key")}
pathName="/api/store"
/>
</SectionContainer>
@@ -253,7 +257,8 @@ const App = () => {
area: "store",
section: "http-compression"
}}
sectionTitle="HTTP Compression"
reportLink={formatReportLink("store", "HTTP Compression")}
pathName="/api/store"
/>
</SectionContainer>
@@ -456,7 +461,8 @@ relations like `collection`.
area: "store",
section: "expand"
}}
sectionTitle="Expanding Fields"
reportLink={formatReportLink("store", "Expanding Fields")}
pathName="/api/store"
/>
</SectionContainer>
@@ -776,7 +782,8 @@ export default Products`,
area: "store",
section: "select-fields"
}}
sectionTitle="Selecting Fields"
reportLink={formatReportLink("store", "Selecting Fields")}
pathName="/api/store"
/>
</SectionContainer>
@@ -916,7 +923,8 @@ curl -g "http://localhost:9000/store/products?created_at[lt]=2023-02-17&created_
area: "store",
section: "query-parameters"
}}
sectionTitle="Query Parameter Types"
reportLink={formatReportLink("store", "Query Parameter Types")}
pathName="/api/store"
/>
</SectionContainer>
@@ -939,8 +947,8 @@ returning the resulting entities.
You can use the `offset` query parameter to change between pages. For
example, if the limit is 50, at page 1 the offset should be 0; at page 2 the
offset should be 50, and so on.
example, if the limit is `50`, at page `1` the offset should be `0`; at page `2` the
offset should be `50`, and so on.
For example, to limit the number of products returned in the List Products
@@ -1140,7 +1148,8 @@ order.
area: "store",
section: "pagination"
}}
sectionTitle="Pagination"
reportLink={formatReportLink("store", "Pagination")}
pathName="/api/store"
/>
</SectionContainer>

View File

@@ -0,0 +1,54 @@
import clsx from "clsx"
import "../../../css/globals.css"
import Navbar from "@/components/Navbar"
import { Inter } from "next/font/google"
import { Roboto_Mono } from "next/font/google"
import Providers from "../../../providers"
import { Sidebar } from "docs-ui"
export const metadata = {
title: "Medusa API Reference",
description: "Check out Medusa's API reference",
}
const inter = Inter({
subsets: ["latin"],
variable: "--font-inter",
weight: ["400", "500"],
})
const robotoMono = Roboto_Mono({
subsets: ["latin"],
variable: "--font-roboto-mono",
})
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en" className={clsx("h-full w-full")}>
<body
className={clsx(
inter.variable,
robotoMono.variable,
"bg-docs-bg dark:bg-docs-bg-dark font-base text-medium h-full w-full",
"text-medusa-fg-subtle dark:text-medusa-fg-subtle-dark"
)}
>
<Providers>
<div className="w-full">
<Navbar />
<div className="max-w-xxl mx-auto flex w-full px-1.5">
<Sidebar />
<main className="lg:w-ref-main relative mt-4 w-full flex-1 lg:mt-7">
{children}
</main>
</div>
</div>
</Providers>
</body>
</html>
)
}

View File

Before

Width:  |  Height:  |  Size: 253 KiB

After

Width:  |  Height:  |  Size: 253 KiB

View File

@@ -6,7 +6,7 @@ import Section from "@/components/Section"
import Tags from "@/components/Tags"
import type { Area } from "@/types/openapi"
import DividedLayout from "@/layouts/Divided"
import capitalize from "@/utils/capitalize"
import { capitalize } from "docs-ui"
import PageTitleProvider from "../../../providers/page-title"
type ReferencePageProps = {

View File

Before

Width:  |  Height:  |  Size: 253 KiB

After

Width:  |  Height:  |  Size: 253 KiB

Some files were not shown because too many files have changed in this diff Show More