docs: make code blocks collapsible (#7606)

* added collapsible code feature

* fixed side shadow

* fix build errors

* change design

* make code blocks collapsible
This commit is contained in:
Shahed Nasser
2024-06-05 10:28:41 +03:00
committed by GitHub
parent dc087bf310
commit 4a6327e497
44 changed files with 815 additions and 446 deletions

View File

@@ -72,7 +72,7 @@ For example:
export const highlights = [["18", "parseCorsOrigins", "A utility function that parses the CORS configurations in `medusa-config.js`"]]
```ts title="src/api/middlewares.ts" highlights={highlights}
```ts title="src/api/middlewares.ts" highlights={highlights} collapsibleLines="1-7" expandButtonLabel="Show Imports"
import {
ConfigModule,
MiddlewaresConfig,

View File

@@ -57,7 +57,7 @@ You can access the logged-in customers ID in all API routes starting with `/s
For example:
```ts title="src/api/store/customers/me/custom/route.ts" highlights={[["16", "", "Access the logged-in customer's ID."]]}
```ts title="src/api/store/customers/me/custom/route.ts" highlights={[["16", "", "Access the logged-in customer's ID."]]} collapsibleLines="1-7" expandButtonLabel="Show Imports"
import type {
AuthenticatedMedusaRequest,
MedusaResponse,
@@ -90,7 +90,7 @@ You can access the logged-in admin users ID in all API Routes starting with `
For example:
```ts title="src/api/admin/custom/route.ts" highlights={[["16", "req.user.userId", "Access the logged-in admin user's ID."]]}
```ts title="src/api/admin/custom/route.ts" highlights={[["16", "req.user.userId", "Access the logged-in admin user's ID."]]} collapsibleLines="1-7" expandButtonLabel="Show Imports"
import type {
AuthenticatedMedusaRequest,
MedusaResponse,
@@ -125,12 +125,11 @@ To protect custom API Routes that dont start with `/store/customers/me` or `/
For example:
export const highlights = [
["11", "authenticate", "Only authenticated admin users can access routes starting with `/custom/admin`"],
["17", "authenticate", "Only authenticated customers can access routes starting with `/custom/customers`"]
["8", "authenticate", "Only authenticated admin users can access routes starting with `/custom/admin`"],
["14", "authenticate", "Only authenticated customers can access routes starting with `/custom/customers`"]
]
```ts title="src/api/middlewares.ts" highlights={highlights}
// TODO update import
import { MiddlewaresConfig, authenticate } from "@medusajs/medusa"
export const config: MiddlewaresConfig = {

View File

@@ -35,7 +35,7 @@ For building relationships between data models in different modules, refer to th
The following example showcase a data model with common definitions:
```ts
```ts collapsibleLines="1-10" expandButtonLabel="Show Imports"
import {
Entity,
Enum,

View File

@@ -20,7 +20,7 @@ When retrieving or listing records of that data model, records having their `del
To create a soft-deletable model, first, add the following filter decorator to the data model class:
```ts title="src/module/hello/models/my-soft-deletable.ts" highlights={[["7"]]}
```ts title="src/module/hello/models/my-soft-deletable.ts" highlights={[["7"]]} collapsibleLines="1-7" expandButtonLabel="Show Imports"
// other imports...
import { Entity, Filter } from "@mikro-orm/core"
import { DALUtils } from "@medusajs/utils"

View File

@@ -20,10 +20,10 @@ export const highlights = [
["9", '"data" in data ? data.data.id : data.id', "The payload data is either in `data.data` or directly in `data`."]
]
```ts title="src/subscribers/product-created.ts" highlights={highlights}
import {
```ts title="src/subscribers/product-created.ts" highlights={highlights} collapsibleLines="1-5" expandButtonLabel="Show Imports"
import type {
SubscriberArgs,
type SubscriberConfig,
SubscriberConfig,
} from "@medusajs/medusa"
export default async function productCreateHandler({

View File

@@ -48,7 +48,7 @@ When the loader function is created outside a module, it receives the Medusa con
For example:
```ts title="src/loaders/hello-world.ts"
```ts title="src/loaders/hello-world.ts" collapsibleLines="1-5" expandButtonLabel="Show Imports"
import { MedusaContainer } from "@medusajs/medusa"
import { IProductModuleService } from "@medusajs/types"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"

View File

@@ -40,7 +40,7 @@ The Medusa application resolves these relationships while maintaining isolation
Consider youre creating a data model that adds custom fields associated with a product:
```ts title="src/modules/hello/models/custom-product-data.ts" highlights={[["17"]]}
```ts title="src/modules/hello/models/custom-product-data.ts" highlights={[["17"]]} collapsibleLines="1-8" expandButtonLabel="Show Imports"
import { BaseEntity } from "@medusajs/utils"
import {
Entity,
@@ -83,7 +83,7 @@ export const relationshipsHighlight = [
["42", "foreignKey", "The name of the field in your data models referencing the other modules model."],
]
```ts title="src/modules/hello/service.ts" highlights={relationshipsHighlight}
```ts title="src/modules/hello/service.ts" highlights={relationshipsHighlight} collapsibleLines="1-6" expandButtonLabel="Show Imports"
// other imports...
import { MyCustom } from "./models/custom-product-data"
import { CustomProductData } from "./models/custom-product-data"

View File

@@ -12,28 +12,27 @@ The remote link is a class with utility methods to manage links defined by the l
For example:
```ts
```ts collapsibleLines="1-9" expandButtonLabel="Show Imports"
import {
MedusaRequest,
MedusaResponse,
} from "@medusajs/medusa"
import {
ModuleRegistrationName,
RemoteLink,
} from "@medusajs/modules-sdk"
import {
ContainerRegistrationKeys,
ContainerRegistrationKeys,
} from "@medusajs/utils"
import {
RemoteLink,
} from "@medusajs/modules-sdk"
export async function POST(
req: MedusaRequest,
res: MedusaResponse
): Promise<void> {
const remoteLink: RemoteLink = req.scope.resolve(
ContainerRegistrationKeys.REMOTE_LINK
)
// ...
const remoteLink: RemoteLink = req.scope.resolve(
ContainerRegistrationKeys.REMOTE_LINK
)
// ...
}
```

View File

@@ -28,7 +28,7 @@ export const exampleHighlights = [
["27", "remoteQuery", "Run the query using the remote query."]
]
```ts title="src/api/store/query/route.ts" highlights={exampleHighlights} apiTesting testApiMethod="GET" testApiUrl="http://localhost:9000/store/query"
```ts title="src/api/store/query/route.ts" highlights={exampleHighlights} apiTesting testApiMethod="GET" testApiUrl="http://localhost:9000/store/query" collapsibleLines="1-12" expandButtonLabel="Show Imports"
import {
MedusaRequest,
MedusaResponse,
@@ -210,7 +210,7 @@ The remote query function alternatively accepts a string with GraphQL syntax as
### Basic GraphQL usage
```ts title="src/api/store/query/route.ts" apiTesting testApiMethod="GET" testApiUrl="http://localhost:9000/store/query"
```ts title="src/api/store/query/route.ts" apiTesting testApiMethod="GET" testApiUrl="http://localhost:9000/store/query" collapsibleLines="1-10" expandButtonLabel="Show Imports"
import {
MedusaRequest,
MedusaResponse,

View File

@@ -146,7 +146,7 @@ export const typeArgsHighlights = [
["27", "AllModelsDTO", "The expected input/output type of the generated methods of every data model."],
]
```ts title="src/modules/hello/service.ts" highlights={typeArgsHighlights}
```ts title="src/modules/hello/service.ts" highlights={typeArgsHighlights} collapsibleLines="1-22" expandButtonLabel="Show More"
import { ModulesSdkUtils } from "@medusajs/utils"
import { MyCustom } from "./models/my-custom"

View File

@@ -19,7 +19,7 @@ export const highlights = [
["14", "throwOnError", "Specify that errors occuring during the workflow's execution should be returned, not thrown."],
]
```ts title="src/api/store/workflows/route.ts" highlights={highlights}
```ts title="src/api/store/workflows/route.ts" highlights={highlights} collapsibleLines="1-6" expandButtonLabel="Show Imports"
import type {
MedusaRequest,
MedusaResponse,

View File

@@ -46,7 +46,7 @@ export const updateProductHighlights = [
["39", "", "Revert the products data using the `previousProductData` passed from the step to the compensation function."]
]
```ts title="src/workflows/update-product-erp/steps/update-product.ts" highlights={updateProductHighlights}
```ts title="src/workflows/update-product-erp/steps/update-product.ts" highlights={updateProductHighlights} collapsibleLines="1-9" expandButtonLabel="Show Imports"
import {
createStep,
StepResponse,
@@ -145,7 +145,7 @@ export const updateErpHighlights = [
["37", "updateProductErpData", "Revert the product's data in the ERP system to its previous state using the `previousErpData`."]
]
```ts title="src/workflows/update-product-erp/steps/update-erp.ts" highlights={updateErpHighlights}
```ts title="src/workflows/update-product-erp/steps/update-erp.ts" highlights={updateErpHighlights} collapsibleLines="1-8" expandButtonLabel="Show Imports"
import {
createStep,
StepResponse,
@@ -208,7 +208,7 @@ With the steps ready, you'll create the workflow that runs these steps to update
Change the content of `src/workflows/update-product-erp/index.ts` to the following:
```ts title="src/workflows/update-product-erp/index.ts"
```ts title="src/workflows/update-product-erp/index.ts" collapsibleLines="1-6" expandButtonLabel="Show Imports"
import { createWorkflow } from "@medusajs/workflows-sdk"
import { UpdateProductDTO, ProductDTO } from "@medusajs/types"
import updateProduct from "./steps/update-product"

View File

@@ -12,7 +12,7 @@ Errors can occur in a workflow. To avoid data inconsistency, define a function t
For example:
```ts title="src/workflows/hello-world.ts" highlights={[["16"], ["17"], ["18"]]}
```ts title="src/workflows/hello-world.ts" highlights={[["16"], ["17"], ["18"]]} collapsibleLines="1-6" expandButtonLabel="Show Imports"
// other imports...
import {
createStep,
@@ -52,7 +52,7 @@ const step2 = createStep(
2. Use the steps in a workflow. For example:
```ts title="src/workflows/hello-world.ts"
```ts title="src/workflows/hello-world.ts" collapsibleLines="1-7" expandButtonLabel="Show Imports"
import {
// other imports...
createWorkflow,
@@ -81,7 +81,7 @@ export default myWorkflow
3. Execute the workflow from a resource, such as an API route:
```ts title="src/api/store/workflow/route.ts"
```ts title="src/api/store/workflow/route.ts" collapsibleLines="1-6" expandButtonLabel="Show Imports"
import type {
MedusaRequest,
MedusaResponse,

View File

@@ -22,7 +22,7 @@ A workflow is considered long-running if at least one step has its `async` confi
For example, consider the following workflow and steps:
```ts title="src/workflows/hello-world.ts" highlights={[["13"]]}
```ts title="src/workflows/hello-world.ts" highlights={[["13"]]} collapsibleLines="1-10" expandButtonLabel="Show More"
import {
createStep,
createWorkflow,
@@ -88,7 +88,7 @@ export const highlights = [
["24", "subscribe", "Subscribe to status changes of the workflow execution."],
]
```ts title="src/api/store/workflows/route.ts" highlights={highlights}
```ts title="src/api/store/workflows/route.ts" highlights={highlights} collapsibleLines="1-11" expandButtonLabel="Show Imports"
import type {
MedusaRequest,
MedusaResponse,

View File

@@ -19,7 +19,7 @@ export const highlights = [
["23", "parallelize", "Run the steps passed as parameters in parallel."],
]
```ts highlights={highlights}
```ts highlights={highlights} collapsibleLines="1-12" expandButtonLabel="Show Imports"
import {
createWorkflow,
parallelize,

View File

@@ -12,7 +12,7 @@ By default, when an error occurs in a step, the step and the workflow fail, and
You can configure the step to retry on failure. The `createStep` function can accept a configuration object instead of the steps name as a first parameter:
```ts title="src/workflows/hello-world.ts" highlights={[["10"]]}
```ts title="src/workflows/hello-world.ts" highlights={[["10"]]} collapsibleLines="1-6" expandButtonLabel="Show Imports"
import {
createStep,
StepResponse,

View File

@@ -20,7 +20,7 @@ Timeout doesn't stop the execution of a running step. The timeout only affects t
For example:
```ts title="src/workflows/hello-world.ts" highlights={[["22"]]}
```ts title="src/workflows/hello-world.ts" highlights={[["22"]]} collapsibleLines="1-16" expandButtonLabel="Show More"
import {
createStep,
createWorkflow,

View File

@@ -1,77 +0,0 @@
export const metadata = {
title: `${pageNumber} Services`,
}
# {metadata.title}
In this chapter, you'll learn what services are and how to create a service.
## What is a Service?
A service is a class that holds methods related to a business logic or commerce functionality. For example, the `ProductService` holds methods to retrieve and manage products.
---
## How to Create a Service
Services are created in a TypeScript or JavaScript file under the `src/services` directory of your Medusa application.
For example, to create a `HelloWorld` service, create the file `src/services/hello-world.ts` with the following content:
```ts title="src/services/hello-world.ts"
class HelloWorld {
// TODO add methods
}
export default HelloWorld
```
<Note title="Tip">
A service's file name must be the kebab-case name of the service without the word `Service`.
</Note>
---
## When to Use
<Note title="Use services when" type="success">
- You're implementing custom commerce functionality to be reused across the Medusa application.
- You're integrating a third-party service, such as an ERP system.
</Note>
---
## Resolve Resources
In a service's constructor, you can resolve other services or resources of your Medusa application using the Medusa container.
For example, you can resolve the `IProductModuleService` to use it in your methods:
```ts title="src/services/hello-world.ts" highlights={[["10"]]}
import { IProductModuleService } from "@medusajs/types"
type InjectedDependencies = {
productModuleService: IProductModuleService
}
class HelloWorldService {
protected productModuleService: IProductModuleService
constructor({ productModuleService }: InjectedDependencies) {
this.productModuleService = productModuleService
}
async getMessage(): Promise<string> {
const [, count] =
await this.productModuleService.listAndCount()
return `You have ${count} products`
}
}
export default HelloWorldService
```

View File

@@ -20,7 +20,7 @@ export const highlights = [
["21", "data", "The data to pass to the template defined in the third-party service."]
]
```ts title="src/subscribers/product-created.ts" highlights={highlights}
```ts title="src/subscribers/product-created.ts" highlights={highlights} collapsibleLines="1-7" expandButtonLabel="Show Imports"
import type {
SubscriberArgs,
SubscriberConfig,

View File

@@ -146,7 +146,7 @@ export const highlights = [
["21", "data", "The data to pass to the template defined in SendGrid."]
]
```ts title="src/subscribers/product-created.ts" highlights={highlights}
```ts title="src/subscribers/product-created.ts" highlights={highlights} collapsibleLines="1-7" expandButtonLabel="Show Imports"
import type {
SubscriberArgs,
SubscriberConfig,

View File

@@ -119,7 +119,7 @@ In this guide, youll find common examples of how you can use the API Key Modu
<CodeTabs groupId="app-type">
<CodeTab label="Medusa API Router" value="medusa">
```ts
```ts collapsibleLines="1-9" expandButtonLabel="Show Imports"
import {
AuthenticatedMedusaRequest,
MedusaResponse
@@ -257,7 +257,7 @@ In this guide, youll find common examples of how you can use the API Key Modu
<CodeTabs groupId="app-type">
<CodeTab label="Medusa API Router" value="medusa">
```ts
```ts collapsibleLines="1-8" expandButtonLabel="Show Imports"
import {
AuthenticatedMedusaRequest,
MedusaResponse

View File

@@ -19,7 +19,7 @@ This example uses the [jsonwebtoken NPM package](https://www.npmjs.com/package/j
<CodeTabs groupId="app-type">
<CodeTab label="Medusa API Router" value="medusa">
```ts
```ts collapsibleLines="1-10" expandButtonLabel="Show Imports"
import { MedusaRequest, MedusaResponse } from "@medusajs/medusa"
import {
IAuthModuleService,
@@ -122,7 +122,7 @@ This example uses the [jsonwebtoken NPM package](https://www.npmjs.com/package/j
<CodeTabs groupId="app-type">
<CodeTab label="Medusa API Router" value="medusa">
```ts
```ts collapsibleLines="1-10" expandButtonLabel="Show Imports"
import { MedusaRequest, MedusaResponse } from "@medusajs/medusa"
import {
IAuthModuleService,
@@ -171,7 +171,7 @@ This example uses the [jsonwebtoken NPM package](https://www.npmjs.com/package/j
</CodeTab>
<CodeTab label="Next.js App Router" value="nextjs">
```ts
```ts collapsibleLines="1-7" expandButtonLabel="Show Imports"
import { NextResponse } from "next/server"
import {

View File

@@ -41,7 +41,7 @@ Learn more about actions in the [Promotion Modules documentation](../../promo
</Note>
```ts
```ts collapsibleLines="1-8" expandButtonLabel="Show Imports"
import {
ComputeActionAdjustmentLine,
ComputeActionItemLine,
@@ -101,7 +101,7 @@ The `computeActions` method accepts the existing adjustments of line items and s
Then, use the returned `addItemAdjustment` and `addShippingMethodAdjustment` actions to set the carts line item and the shipping methods adjustments.
```ts
```ts collapsibleLines="1-9" expandButtonLabel="Show Imports"
import {
AddItemAdjustmentAction,
AddShippingMethodAdjustment,

View File

@@ -41,7 +41,7 @@ Learn more about actions in the [Promotion Modules documentation](../../promo
</Note>
```ts
```ts collapsibleLines="1-10" expandButtonLabel="Show Imports"
import {
ComputeActionAdjustmentLine,
ComputeActionItemLine,
@@ -103,7 +103,7 @@ The `computeActions` method accepts the existing adjustments of line items and s
Then, use the returned `addItemAdjustment` and `addShippingMethodAdjustment` actions to set the orders line items and the shipping methods adjustments.
```ts
```ts collapsibleLines="1-9" expandButtonLabel="Show Imports"
import {
AddItemAdjustmentAction,
AddShippingMethodAdjustment,

View File

@@ -323,7 +323,7 @@ In this document, youll find common examples of how you can use the Pricing M
<CodeTabs groupId="app-type">
<CodeTab value="medusa" label="Medusa API Router">
```ts
```ts collapsibleLines="1-8" expandButtonLabel="Show Imports"
import { MedusaRequest, MedusaResponse } from "@medusajs/medusa"
import {
IPricingModuleService,

View File

@@ -1,4 +1,4 @@
import { Table, LegacyCodeTabs } from "docs-ui"
import { Table, CodeTabs, CodeTab } from "docs-ui"
export const metadata = {
title: `Medusa JS Client`,
@@ -267,13 +267,11 @@ Once the user or customer is authenticated successfully, the Medusa client autom
For example:
<LegacyCodeTabs tabs={[
{
label: "Admin User",
value: "user",
code: {
lang: "ts",
source: `import Medusa from "@medusajs/medusa-js"
<CodeTabs group="client-authentication-type">
<CodeTab label="Admin User" value="user">
```ts
import Medusa from "@medusajs/medusa-js"
const medusa = new Medusa({
baseUrl: MEDUSA_BACKEND_URL,
maxRetries: 3,
@@ -282,15 +280,14 @@ For example:
email: "user@example.com",
password: "supersecret",
})
// send authenticated requests now`
}
},
{
label: "Customer",
value: "customer",
code: {
lang: "ts",
source: `import Medusa from "@medusajs/medusa-js"
// send authenticated requests now
```
</CodeTab>
<CodeTab label="Customer" value="customer">
```ts
import Medusa from "@medusajs/medusa-js"
const medusa = new Medusa({
baseUrl: MEDUSA_BACKEND_URL,
maxRetries: 3,
@@ -299,10 +296,11 @@ For example:
email: "user@example.com",
password: "supersecret",
})
// send authenticated requests now`
}
}
]} group="client-authentication-type" />
// send authenticated requests now
```
</CodeTab>
</CodeTabs>
### Cookie Session ID
@@ -314,13 +312,11 @@ Once the user or customer is authenticated successfully, the Medusa client sets
For example:
<LegacyCodeTabs tabs={[
{
label: "Admin User",
value: "user",
code: {
lang: "ts",
source: `import Medusa from "@medusajs/medusa-js"
<CodeTabs group="client-authentication-type">
<CodeTab label="Admin User" value="user">
```ts
import Medusa from "@medusajs/medusa-js"
const medusa = new Medusa({
baseUrl: MEDUSA_BACKEND_URL,
maxRetries: 3,
@@ -329,15 +325,14 @@ For example:
email: "user@example.com",
password: "supersecret",
})
// send authenticated requests now`
}
},
{
label: "Customer",
value: "customer",
code: {
lang: "ts",
source: `import Medusa from "@medusajs/medusa-js"
// send authenticated requests now
```
</CodeTab>
<CodeTab label="Customer" value="customer">
```ts
import Medusa from "@medusajs/medusa-js"
const medusa = new Medusa({
baseUrl: MEDUSA_BACKEND_URL,
maxRetries: 3,
@@ -346,10 +341,11 @@ For example:
email: "user@example.com",
password: "user@example.com",
})
// send authenticated requests now`
}
}
]} group="client-authentication-type" />
// send authenticated requests now
```
</CodeTab>
</CodeTabs>
### API Key
@@ -357,13 +353,11 @@ You can authenticate admin users with a personal API Token.
If a user doesn't have a personal API token, create one with the [admin.users.update](/references/js-client/AdminUsersResource#update) method or the [Update User API route](https://docs.medusajs.com/api/admin#users_postusersuser):
<LegacyCodeTabs tabs={[
{
label: "JS Client",
value: "js-client",
code: {
lang: "ts",
source: `import Medusa from "@medusajs/medusa-js"
<CodeTabs group="client-type">
<CodeTab label="JS Client" value="js-client">
```ts
import Medusa from "@medusajs/medusa-js"
const medusa = new Medusa({
baseUrl: MEDUSA_BACKEND_URL,
maxRetries: 3,
@@ -374,23 +368,23 @@ If a user doesn't have a personal API token, create one with the [admin.users.up
})
.then(({ user }) => {
console.log(user.api_token)
})`
}
},
{
label: "cURL",
value: "curl",
code: {
lang: "bash",
source: `curl -L -X POST '<BACKEND_URL>/admin/users/<USER_ID>' \\
})
```
</CodeTab>
<CodeTab label="cURL" value="curl">
```bash
curl -L -X POST '<BACKEND_URL>/admin/users/<USER_ID>' \\
-H 'Cookie: connect.sid={sid}' \\
-H 'Content-Type: application/json' \\
--data-raw '{
"api_token": "{api_token}"
}'`
}
}
]} group="client-type" />
}'
```
</CodeTab>
</CodeTabs>
Then, initialize the Medusa client passing it the `apiKey` option:

View File

@@ -1,4 +1,4 @@
import { Table, LegacyCodeTabs } from "docs-ui"
import { Table, CodeTabs, CodeTab } from "docs-ui"
export const metadata = {
title: `Medusa React`,
@@ -216,13 +216,11 @@ There are two ways to authenticate an admin user:
For example:
<LegacyCodeTabs tabs={[
{
value: "useadminlogin",
label: "useAdminLogin hook",
code: {
lang: "ts",
source: `import React from "react"
<CodeTabs group="admin-auth">
<CodeTab label="useAdminLogin hook" value="useadminlogin">
```ts
import React from "react"
import { useAdminLogin } from "medusa-react"
const Login = () => {
@@ -244,15 +242,14 @@ For example:
// ...
}
export default Login`
}
},
{
value: "apikey",
label: "apikey Option",
code: {
lang: "tsx",
source: `import { MedusaProvider } from "medusa-react"
export default Login
```
</CodeTab>
<CodeTab label="apikey Option" value="apikey">
```tsx
import { MedusaProvider } from "medusa-react"
import Storefront from "./Storefront"
import { QueryClient } from "@tanstack/react-query"
import React from "react"
@@ -271,10 +268,11 @@ For example:
)
}
export default App`
}
}
]} group="admin-auth" />
export default App
```
</CodeTab>
</CodeTabs>
### Customer Authentication

View File

@@ -1,4 +1,4 @@
import { LegacyCodeTabs } from "docs-ui"
import { CodeTabs, CodeTab } from "docs-ui"
If you install the Medusa CLI tool with Yarn, then try to use the CLI tool but get the error:
@@ -8,28 +8,23 @@ command not found: medusa
You have to add Yarns install location to the PATH variable:
<LegacyCodeTabs
tabs={[
{
label: "MacOS / Linux",
value: "unix",
code: {
lang: "bash",
source: `export PATH="$(yarn global bin):$PATH"`
}
},
{
label: "Windows",
value: "windows",
code: {
lang: "bash",
source: `# MAKE SURE TO INCLUDE %path%
<CodeTabs group="operating-systems">
<CodeTab label="MacOS / Linux" value="unix">
```plain
export PATH="$(yarn global bin):$PATH
```
</CodeTab>
<CodeTab label="Windows" value="windows">
```bash
# MAKE SURE TO INCLUDE %path%
setx path "%path%;c:\\users\\YOURUSERNAME\\appdata\\local\\yarnbin"
# YOURUSERNAME is your account username`
}
}
]}
group="operating-systems"
/>
# YOURUSERNAME is your account username
```
</CodeTab>
</CodeTabs>
You can learn more in [Yarns documentation](https://classic.yarnpkg.com/en/docs/cli/global#adding-the-install-location-to-your-path).

View File

@@ -1,26 +1,24 @@
import { LegacyCodeTabs } from "docs-ui"
import { CodeTabs, CodeTab } from "docs-ui"
This error can occur while installing any of Medusa's projects (for example, Next.js Starter Template). There is no specific cause to this error.
One way to resolve it is by removing the `node_modules` directory in the project and re-installing the dependencies:
<LegacyCodeTabs tabs={[
{
label: "MacOS / Linux",
value: "unix",
code: {
lang: "bash",
source: `rm -rf node_modules
yarn install`
}
},
{
label: "Windows",
value: "windows",
code: {
lang: "bash",
source: `rd /s /q node_modules
yarn install`
}
}
]} group="operating-systems" />
<CodeTabs group="operating-systems">
<CodeTab label="MacOS / Linux" value="unix">
```bash
rm -rf node_modules
yarn install
```
</CodeTab>
<CodeTab label="Windows" value="windows">
```bash
rd /s /q node_modules
yarn install
```
</CodeTab>
</CodeTabs>

View File

@@ -227,6 +227,10 @@ export const filesMap = [
"filePath": "/www/apps/resources/app/architectural-modules/workflow-engine/redis/page.mdx",
"pathname": "/architectural-modules/workflow-engine/redis"
},
{
"filePath": "/www/apps/resources/app/commerce-modules/api-key/concepts/page.mdx",
"pathname": "/commerce-modules/api-key/concepts"
},
{
"filePath": "/www/apps/resources/app/commerce-modules/api-key/events/_events-table/page.mdx",
"pathname": "/commerce-modules/api-key/events/_events-table"
@@ -247,10 +251,6 @@ export const filesMap = [
"filePath": "/www/apps/resources/app/commerce-modules/api-key/relations-to-other-modules/page.mdx",
"pathname": "/commerce-modules/api-key/relations-to-other-modules"
},
{
"filePath": "/www/apps/resources/app/commerce-modules/api-key/tokens/page.mdx",
"pathname": "/commerce-modules/api-key/tokens"
},
{
"filePath": "/www/apps/resources/app/commerce-modules/auth/auth-flows/page.mdx",
"pathname": "/commerce-modules/auth/auth-flows"
@@ -331,6 +331,10 @@ export const filesMap = [
"filePath": "/www/apps/resources/app/commerce-modules/currency/page.mdx",
"pathname": "/commerce-modules/currency"
},
{
"filePath": "/www/apps/resources/app/commerce-modules/currency/relations-to-other-modules/page.mdx",
"pathname": "/commerce-modules/currency/relations-to-other-modules"
},
{
"filePath": "/www/apps/resources/app/commerce-modules/customer/customer-accounts/page.mdx",
"pathname": "/commerce-modules/customer/customer-accounts"
@@ -687,6 +691,10 @@ export const filesMap = [
"filePath": "/www/apps/resources/app/commerce-modules/store/page.mdx",
"pathname": "/commerce-modules/store"
},
{
"filePath": "/www/apps/resources/app/commerce-modules/store/relations-to-other-modules/page.mdx",
"pathname": "/commerce-modules/store/relations-to-other-modules"
},
{
"filePath": "/www/apps/resources/app/commerce-modules/tax/events/_events-table/page.mdx",
"pathname": "/commerce-modules/tax/events/_events-table"
@@ -743,10 +751,6 @@ export const filesMap = [
"filePath": "/www/apps/resources/app/commerce-modules/user/user-creation-flows/page.mdx",
"pathname": "/commerce-modules/user/user-creation-flows"
},
{
"filePath": "/www/apps/resources/app/configurations/_medusa-admin/page.mdx",
"pathname": "/configurations/_medusa-admin"
},
{
"filePath": "/www/apps/resources/app/contribution-guidelines/_admin-translations/page.mdx",
"pathname": "/contribution-guidelines/_admin-translations"
@@ -931,14 +935,6 @@ export const filesMap = [
"filePath": "/www/apps/resources/app/troubleshooting/_transaction-promise-all/page.mdx",
"pathname": "/troubleshooting/_transaction-promise-all"
},
{
"filePath": "/www/apps/resources/app/troubleshooting/admin-sign-in/page.mdx",
"pathname": "/troubleshooting/admin-sign-in"
},
{
"filePath": "/www/apps/resources/app/troubleshooting/admin-webpack-build-error/page.mdx",
"pathname": "/troubleshooting/admin-webpack-build-error"
},
{
"filePath": "/www/apps/resources/app/troubleshooting/cors-errors/page.mdx",
"pathname": "/troubleshooting/cors-errors"

View File

@@ -37,8 +37,8 @@ export const generatedSidebar = [
{
"loaded": true,
"isPathHref": true,
"path": "/commerce-modules/api-key/tokens",
"title": "Tokens",
"path": "/commerce-modules/api-key/concepts",
"title": "API Key Concepts",
"children": []
},
{
@@ -863,6 +863,20 @@ export const generatedSidebar = [
"title": "Examples",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"title": "Concepts",
"children": [
{
"loaded": true,
"isPathHref": true,
"path": "/commerce-modules/currency/relations-to-other-modules",
"title": "Relation to Modules",
"children": []
}
]
},
{
"loaded": true,
"isPathHref": true,
@@ -5068,6 +5082,20 @@ export const generatedSidebar = [
"title": "Examples",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"title": "Concepts",
"children": [
{
"loaded": true,
"isPathHref": true,
"path": "/commerce-modules/store/relations-to-other-modules",
"title": "Relation to Modules",
"children": []
}
]
},
{
"loaded": true,
"isPathHref": true,
@@ -5236,7 +5264,7 @@ export const generatedSidebar = [
"loaded": true,
"isPathHref": true,
"path": "/commerce-modules/tax/tax-calculation-with-provider",
"title": "Tax Calculation",
"title": "Tax Calculation and Providers",
"children": []
}
]
@@ -5246,13 +5274,6 @@ export const generatedSidebar = [
"isPathHref": true,
"title": "References",
"children": [
{
"loaded": true,
"isPathHref": true,
"path": "/references/tax/provider",
"title": "Tax Provider Reference",
"children": []
},
{
"loaded": true,
"isPathHref": true,
@@ -7144,28 +7165,6 @@ export const generatedSidebar = [
"children": []
}
]
},
{
"loaded": true,
"isPathHref": true,
"title": "Medusa Admin",
"hasTitleStyling": true,
"children": [
{
"loaded": true,
"isPathHref": true,
"path": "/troubleshooting/admin-sign-in",
"title": "Signing In",
"children": []
},
{
"loaded": true,
"isPathHref": true,
"path": "/troubleshooting/admin-custom-hooks-error",
"title": "Custom Hooks Error",
"children": []
}
]
}
]
}

View File

@@ -2,7 +2,7 @@
import {
SearchProvider as UiSearchProvider,
AiAssistantCommandIcon,
AiAssistantIcon,
AiAssistantProvider,
searchFiltersV1,
} from "docs-ui"
@@ -48,7 +48,7 @@ const SearchProvider = ({ children }: SearchProviderProps) => {
commands={[
{
name: "ai-assistant",
icon: <AiAssistantCommandIcon />,
icon: <AiAssistantIcon />,
component: (
<AiAssistantProvider
apiUrl={process.env.NEXT_PUBLIC_AI_ASSISTANT_URL || "temp"}
@@ -61,8 +61,9 @@ const SearchProvider = ({ children }: SearchProviderProps) => {
),
title: "AI Assistant",
badge: {
variant: "purple",
variant: "blue",
children: "Beta",
badgeType: "shaded",
},
},
]}

View File

@@ -12,6 +12,9 @@ export type CodeBlockActionsProps = {
source: string
isSingleLine?: boolean
inHeader: boolean
showGradientBg?: boolean
inInnerCode?: boolean
isCollapsed: boolean
canShowApiTesting?: boolean
blockStyle: CodeBlockStyle
onApiTesting: React.Dispatch<React.SetStateAction<boolean>>
@@ -22,6 +25,9 @@ export type CodeBlockActionsProps = {
export const CodeBlockActions = ({
source,
inHeader,
showGradientBg = true,
inInnerCode = false,
isCollapsed,
isSingleLine = false,
canShowApiTesting = false,
blockStyle,
@@ -45,65 +51,87 @@ export const CodeBlockActions = ({
return (
<div
className={clsx(
"absolute hidden md:flex md:justify-end",
"xs:rounded xs:absolute xs:right-0 xs:top-0 xs:w-[calc(10%+24px)] xs:h-full xs:bg-transparent",
!inHeader && [
"md:right-docs_0.5",
isSingleLine && "md:top-docs_0.25",
!isSingleLine && "md:top-docs_0.5",
],
inHeader && "md:right-docs_1 md:top-docs_0.5"
"absolute hidden md:block",
"xs:rounded xs:absolute xs:right-0 xs:top-0 xs:w-[calc(17%+10px)] xs:h-full"
)}
>
{canShowApiTesting && (
<Tooltip
text="Test API"
tooltipClassName="font-base"
className={clsx(
"h-fit",
!inHeader && "p-[6px]",
inHeader && "px-[6px] pb-[6px]"
)}
>
<PlaySolid
className={clsx("cursor-pointer", iconColor)}
onClick={() => onApiTesting(true)}
/>
</Tooltip>
)}
{!noReport && (
<Tooltip
text="Report Issue"
tooltipClassName="font-base"
className={clsx(
"h-fit",
!inHeader && "p-[6px]",
inHeader && "px-[6px] pb-[6px]"
)}
>
<Link
href={`${GITHUB_ISSUES_PREFIX}&title=${encodeURIComponent(
`Docs(Code Issue): `
)}`}
target="_blank"
<div
className={clsx(
!inHeader &&
showGradientBg && [
inInnerCode &&
"xs:bg-subtle-code-fade-right-to-left dark:xs:bg-subtle-code-fade-right-to-left-dark",
!inInnerCode &&
"xs:bg-base-code-fade-right-to-left dark:xs:bg-base-code-fade-right-to-left-dark",
],
(inHeader || !showGradientBg) && "xs:bg-transparent",
"z-[9] w-full h-full absolute top-0 left-0"
)}
/>
<div
className={clsx(
"md:flex md:justify-end z-[11] relative",
!inHeader && [
"md:pr-docs_0.5",
isCollapsed && "md:pt-docs_2.5",
!isCollapsed && [
isSingleLine && "md:pt-docs_0.25",
!isSingleLine && "md:pt-docs_0.5",
],
],
inHeader && "md:pr-docs_1 md:pt-docs_0.5"
)}
>
{canShowApiTesting && (
<Tooltip
text="Test API"
tooltipClassName="font-base"
className={clsx(
"bg-transparent border-none cursor-pointer rounded",
"[&:not(:first-child)]:ml-docs_0.5",
"inline-flex justify-center items-center invisible xs:visible"
"h-fit",
!inHeader && "p-[6px]",
inHeader && "px-[6px] pb-[6px]"
)}
rel="noreferrer"
>
<ExclamationCircle className={clsx(iconColor)} />
</Link>
</Tooltip>
)}
{!noCopy && (
<CodeBlockCopyAction
source={source}
inHeader={inHeader}
iconColor={iconColor}
/>
)}
<PlaySolid
className={clsx("cursor-pointer", iconColor)}
onClick={() => onApiTesting(true)}
/>
</Tooltip>
)}
{!noReport && (
<Tooltip
text="Report Issue"
tooltipClassName="font-base"
className={clsx(
"h-fit",
!inHeader && "p-[6px]",
inHeader && "px-[6px] pb-[6px]"
)}
>
<Link
href={`${GITHUB_ISSUES_PREFIX}&title=${encodeURIComponent(
`Docs(Code Issue): `
)}`}
target="_blank"
className={clsx(
"bg-transparent border-none cursor-pointer rounded",
"[&:not(:first-child)]:ml-docs_0.5",
"inline-flex justify-center items-center invisible xs:visible"
)}
rel="noreferrer"
>
<ExclamationCircle className={clsx(iconColor)} />
</Link>
</Tooltip>
)}
{!noCopy && (
<CodeBlockCopyAction
source={source}
inHeader={inHeader}
iconColor={iconColor}
/>
)}
</div>
</div>
)
}

View File

@@ -0,0 +1,57 @@
"use client"
import clsx from "clsx"
import React from "react"
import { CollapsibleReturn } from "../../../../hooks"
import { Button } from "@medusajs/ui"
export type CodeBlockCollapsibleButtonProps = {
type: "start" | "end"
expandButtonLabel?: string
className?: string
} & Omit<CollapsibleReturn, "getCollapsibleElms">
export const CodeBlockCollapsibleButton = ({
type,
expandButtonLabel = "Show more",
collapsed,
setCollapsed,
className,
}: CodeBlockCollapsibleButtonProps) => {
if (!collapsed) {
return <></>
}
return (
<>
{type === "start" && (
<Button
className={clsx(
"font-base w-full p-docs_0.5 !shadow-none z-10",
"bg-medusa-contrast-button hover:bg-medusa-contrast-button-hover",
"txt-compact-xsmall text-medusa-contrast-fg-secondary",
type === "start" && "rounded-t-docs_DEFAULT rounded-b-none",
className
)}
onClick={() => setCollapsed(false)}
>
{expandButtonLabel}
</Button>
)}
{type === "end" && (
<Button
className={clsx(
"font-base w-full p-docs_0.5 !shadow-none z-10",
"bg-medusa-contrast-button hover:bg-medusa-contrast-button-hover",
"txt-compact-xsmall text-medusa-contrast-fg-secondary",
"rounded-t-none rounded-b-docs_DEFAULT",
className
)}
onClick={() => setCollapsed(false)}
>
{expandButtonLabel}
</Button>
)}
</>
)
}

View File

@@ -0,0 +1,53 @@
import clsx from "clsx"
import React from "react"
import { CollapsibleReturn } from "../../../../hooks"
export type CodeBlockCollapsibleFadeProps = {
type: "start" | "end"
hasHeader?: boolean
} & Pick<CollapsibleReturn, "collapsed">
export const CodeBlockCollapsibleFade = ({
type,
hasHeader = false,
collapsed,
}: CodeBlockCollapsibleFadeProps) => {
if (!collapsed) {
return <></>
}
return (
<span
className={clsx(
"absolute flex flex-col z-10",
hasHeader && "left-[6px] w-[calc(100%-12px)]",
!hasHeader && "w-full left-0",
type === "start" && [
hasHeader && "top-[44px]",
!hasHeader && "top-[36px]",
],
type === "end" && [
hasHeader && "bottom-[44px]",
!hasHeader && "bottom-[36px]",
]
)}
>
{type === "end" && (
<span
className={clsx(
"w-full h-[56px]",
"bg-code-fade-bottom-to-top dark:bg-code-fade-bottom-to-top-dark"
)}
/>
)}
{type === "start" && (
<span
className={clsx(
"w-full h-[56px]",
"bg-code-fade-top-to-bottom dark:bg-code-fade-top-to-bottom-dark"
)}
/>
)}
</span>
)
}

View File

@@ -0,0 +1,29 @@
"use client"
import React, { useMemo } from "react"
import { CollapsibleReturn } from "../../../../hooks"
export type CodeBlockCollapsibleLinesProps = {
children: React.ReactNode
type: "start" | "end"
} & Omit<CollapsibleReturn, "setCollapsed">
export const CodeBlockCollapsibleLines = ({
children,
type,
collapsed,
getCollapsibleElms,
}: CodeBlockCollapsibleLinesProps) => {
const shownChildren: React.ReactNode = useMemo(() => {
const isStart = type === "start"
return (
<>
{collapsed && Array.isArray(children)
? children.slice(isStart ? -2 : 0, isStart ? undefined : 2)
: children}
</>
)
}, [children, collapsed])
return getCollapsibleElms(shownChildren)
}

View File

@@ -22,6 +22,7 @@ type CodeBlockLineProps = {
lineNumber: number
showLineNumber: boolean
lineNumberColorClassName: string
lineNumberBgClassName: string
noLineNumbers?: boolean
} & Pick<RenderProps, "getLineProps" | "getTokenProps">
@@ -33,6 +34,7 @@ export const CodeBlockLine = ({
getTokenProps,
showLineNumber,
lineNumberColorClassName,
lineNumberBgClassName,
}: CodeBlockLineProps) => {
const lineProps = getLineProps({ line, key: lineNumber })
@@ -241,7 +243,8 @@ export const CodeBlockLine = ({
className={clsx(
"mr-docs_1 table-cell select-none",
"sticky left-0 w-[1%] px-docs_1 text-right",
lineNumberColorClassName
lineNumberColorClassName,
lineNumberBgClassName
)}
>
{lineNumber + 1}

View File

@@ -1,15 +1,19 @@
"use client"
import React, { useMemo, useState } from "react"
import React, { useEffect, useMemo, useRef, useState } from "react"
import clsx from "clsx"
import { HighlightProps, Highlight, themes } from "prism-react-renderer"
import { Highlight, HighlightProps, themes, Token } from "prism-react-renderer"
import { ApiRunner } from "@/components"
import { useColorMode } from "@/providers"
import { CodeBlockHeader, CodeBlockHeaderMeta } from "./Header"
import { CodeBlockLine } from "./Line"
import { ApiAuthType, ApiDataOptions, ApiMethod } from "types"
import { CSSTransition } from "react-transition-group"
import { useCollapsibleCodeLines } from "../.."
import { HighlightProps as CollapsibleHighlightProps } from "@/hooks"
import { CodeBlockActions, CodeBlockActionsProps } from "./Actions"
import { CodeBlockCollapsibleButton } from "./Collapsible/Button"
import { CodeBlockCollapsibleFade } from "./Collapsible/Fade"
export type Highlight = {
line: number
@@ -32,6 +36,8 @@ export type CodeBlockMetaFields = {
noCopy?: boolean
noReport?: boolean
noLineNumbers?: boolean
collapsibleLines?: string
expandButtonLabel?: string
} & CodeBlockHeaderMeta
export type CodeBlockStyle = "loud" | "subtle"
@@ -60,6 +66,8 @@ export const CodeBlock = ({
noReport = false,
noLineNumbers = false,
children,
collapsibleLines,
expandButtonLabel,
...rest
}: CodeBlockProps) => {
if (!source && typeof children === "string") {
@@ -68,6 +76,9 @@ export const CodeBlock = ({
const { colorMode } = useColorMode()
const [showTesting, setShowTesting] = useState(false)
const codeContainerRef = useRef<HTMLDivElement>(null)
const codeRef = useRef<HTMLElement>(null)
const [scrollable, setScrollable] = useState(false)
const hasInnerCodeBlock = useMemo(
() => hasTabs || title.length > 0,
[hasTabs, title]
@@ -107,7 +118,7 @@ export const CodeBlock = ({
const borderColor = useMemo(
() =>
clsx(
blockStyle === "loud" && "border-transparent",
blockStyle === "loud" && "border-0",
blockStyle === "subtle" && [
colorMode === "light" && "border-medusa-border-base",
colorMode === "dark" && "border-medusa-code-border",
@@ -158,10 +169,6 @@ export const CodeBlock = ({
return lowerLang === "json" ? "plain" : lowerLang
}, [lang])
if (!source.length) {
return <></>
}
const transformedHighlights: Highlight[] = highlights
.filter((highlight) => highlight.length !== 0)
.map((highlight) => ({
@@ -170,13 +177,79 @@ export const CodeBlock = ({
tooltipText: highlight.length >= 3 ? highlight[2] : undefined,
}))
const actionsProps: Omit<CodeBlockActionsProps, "inHeader"> = {
source,
canShowApiTesting,
onApiTesting: setShowTesting,
blockStyle,
noReport,
noCopy,
const getLines = (
tokens: Token[][],
highlightProps: CollapsibleHighlightProps,
lineNumberOffset = 0
) =>
tokens.map((line, i) => {
const offsettedLineNumber = i + lineNumberOffset
const highlightedLines = transformedHighlights.filter(
(highlight) => highlight.line - 1 === offsettedLineNumber
)
return (
<CodeBlockLine
line={line}
lineNumber={offsettedLineNumber}
highlights={highlightedLines}
showLineNumber={!noLineNumbers && tokens.length > 1}
key={offsettedLineNumber}
lineNumberColorClassName={lineNumbersColor}
lineNumberBgClassName={innerBgColor}
{...highlightProps}
/>
)
})
const {
getCollapsedLinesElm,
getNonCollapsedLinesElm,
type: collapsibleType,
...collapsibleResult
} = useCollapsibleCodeLines({
collapsibleLinesStr: collapsibleLines,
getLines,
})
useEffect(() => {
if (!codeContainerRef.current || !codeRef.current) {
return
}
setScrollable(
codeContainerRef.current.scrollWidth < codeRef.current.clientWidth
)
}, [codeContainerRef.current, codeRef.current])
const actionsProps: Omit<CodeBlockActionsProps, "inHeader"> = useMemo(
() => ({
source,
canShowApiTesting,
onApiTesting: setShowTesting,
blockStyle,
noReport,
noCopy,
isCollapsed: collapsibleType !== undefined && collapsibleResult.collapsed,
inInnerCode: hasInnerCodeBlock,
showGradientBg: scrollable,
}),
[
source,
canShowApiTesting,
setShowTesting,
blockStyle,
noReport,
noCopy,
collapsibleType,
collapsibleResult,
hasInnerCodeBlock,
scrollable,
]
)
if (!source.length) {
return <></>
}
return (
@@ -233,12 +306,30 @@ export const CodeBlock = ({
tokens,
...rest
}) => (
<div className={clsx(innerBorderClasses, innerBgColor)}>
<div
className={clsx(innerBorderClasses, innerBgColor, "relative")}
ref={codeContainerRef}
>
{collapsibleType === "start" && (
<>
<CodeBlockCollapsibleButton
type={collapsibleType}
expandButtonLabel={expandButtonLabel}
className={innerBorderClasses}
{...collapsibleResult}
/>
<CodeBlockCollapsibleFade
type={collapsibleType}
collapsed={collapsibleResult.collapsed}
hasHeader={hasInnerCodeBlock}
/>
</>
)}
<pre
style={{ ...style, fontStretch: "100%" }}
className={clsx(
"relative !my-0 break-words bg-transparent !outline-none",
"overflow-auto break-words p-0",
"overflow-auto break-words p-0 pr-docs_0.25",
"rounded-docs_DEFAULT",
!hasInnerCodeBlock &&
tokens.length <= 1 &&
@@ -253,24 +344,22 @@ export const CodeBlock = ({
tokens.length > 1 && "py-docs_0.75",
tokens.length <= 1 && "!py-[6px] px-docs_0.5"
)}
ref={codeRef}
>
{tokens.map((line, i) => {
const highlightedLines = transformedHighlights.filter(
(highlight) => highlight.line - 1 === i
)
return (
<CodeBlockLine
line={line}
lineNumber={i}
highlights={highlightedLines}
showLineNumber={!noLineNumbers && tokens.length > 1}
key={i}
lineNumberColorClassName={lineNumbersColor}
{...rest}
/>
)
{collapsibleType === "start" &&
getCollapsedLinesElm({
tokens,
highlightProps: rest,
})}
{getNonCollapsedLinesElm({
tokens,
highlightProps: rest,
})}
{collapsibleType === "end" &&
getCollapsedLinesElm({
tokens,
highlightProps: rest,
})}
</code>
</pre>
{!title && (
@@ -280,6 +369,21 @@ export const CodeBlock = ({
isSingleLine={tokens.length <= 1}
/>
)}
{collapsibleType === "end" && (
<>
<CodeBlockCollapsibleFade
type={collapsibleType}
collapsed={collapsibleResult.collapsed}
hasHeader={hasInnerCodeBlock}
/>
<CodeBlockCollapsibleButton
type={collapsibleType}
expandButtonLabel={expandButtonLabel}
className={innerBorderClasses}
{...collapsibleResult}
/>
</>
)}
</div>
)}
</Highlight>

View File

@@ -3,8 +3,8 @@
import React, { Suspense, cloneElement, useRef, useState } from "react"
import { Loading } from "@/components"
import clsx from "clsx"
import { CSSTransition } from "react-transition-group"
import { DetailsSummary } from "./Summary"
import { useCollapsible } from "../../hooks"
export type DetailsProps = {
openInitial?: boolean
@@ -22,7 +22,11 @@ export const Details = ({
...props
}: DetailsProps) => {
const [open, setOpen] = useState(openInitial)
const [showContent, setShowContent] = useState(openInitial)
const { getCollapsibleElms, setCollapsed } = useCollapsible({
initialValue: !openInitial,
heightAnimation,
onClose: () => setOpen(false),
})
const ref = useRef<HTMLDetailsElement>(null)
const handleToggle = (e: React.MouseEvent<HTMLElement>) => {
@@ -36,10 +40,10 @@ export const Details = ({
return
}
if (open) {
setShowContent(false)
setCollapsed(true)
} else {
setOpen(true)
setShowContent(true)
setCollapsed(false)
}
}
@@ -77,56 +81,11 @@ export const Details = ({
open,
onClick: handleToggle,
})}
<CSSTransition
unmountOnExit
in={showContent}
timeout={150}
onEnter={(node: HTMLElement) => {
if (heightAnimation) {
node.classList.add("transition-[height]")
node.style.height = `0px`
} else {
node.classList.add(
"!mb-docs_2",
"!mt-0",
"translate-y-docs_1",
"transition-transform"
)
}
}}
onEntering={(node: HTMLElement) => {
if (heightAnimation) {
node.style.height = `${node.scrollHeight}px`
}
}}
onEntered={(node: HTMLElement) => {
if (heightAnimation) {
node.style.height = `auto`
}
}}
onExit={(node: HTMLElement) => {
if (heightAnimation) {
node.style.height = `${node.scrollHeight}px`
} else {
node.classList.add("transition-transform", "!-translate-y-docs_1")
setTimeout(() => {
setOpen(false)
}, 100)
}
}}
onExiting={(node: HTMLElement) => {
if (heightAnimation) {
node.style.height = `0px`
setTimeout(() => {
setOpen(false)
}, 100)
}
}}
>
{getCollapsibleElms(
<Suspense fallback={<Loading className="!mb-docs_2 !mt-0" />}>
{children}
</Suspense>
</CSSTransition>
)}
</details>
)
}

View File

@@ -1,3 +1,5 @@
export * from "./use-collapsible"
export * from "./use-collapsible-code-lines"
export * from "./use-copy"
export * from "./use-current-learning-path"
export * from "./use-is-browser"

View File

@@ -0,0 +1,136 @@
"use client"
import {
LineInputProps,
LineOutputProps,
Token,
TokenInputProps,
TokenOutputProps,
} from "prism-react-renderer"
import React, { useCallback, useMemo } from "react"
import { CodeBlockCollapsibleLines } from "../../components/CodeBlock/Collapsible/Lines"
import { useCollapsible } from "../use-collapsible"
export type HighlightProps = {
getLineProps: (input: LineInputProps) => LineOutputProps
getTokenProps: (input: TokenInputProps) => TokenOutputProps
}
export type CollapsibleCodeLines = {
collapsibleLinesStr?: string
getLines: (
token: Token[][],
highlightProps: HighlightProps,
lineNumberOffset?: number
) => React.ReactNode
}
export type CollapsedCodeLinesPosition = "start" | "end"
export const useCollapsibleCodeLines = ({
collapsibleLinesStr,
getLines,
}: CollapsibleCodeLines) => {
const collapsedRange:
| {
start: number
end: number
}
| undefined = useMemo(() => {
if (!collapsibleLinesStr) {
return
}
const splitCollapsedLines = collapsibleLinesStr
.split("-")
.map((lineNumber) => parseInt(lineNumber))
if (
splitCollapsedLines.length !== 2 ||
(splitCollapsedLines[0] !== 1 && splitCollapsedLines[1] < 2)
) {
return
}
return {
start: splitCollapsedLines[0],
end: splitCollapsedLines[1],
}
}, [collapsibleLinesStr])
const type: CollapsedCodeLinesPosition | undefined = useMemo(() => {
if (!collapsedRange) {
return undefined
}
return collapsedRange.start === 1 ? "start" : "end"
}, [collapsedRange])
const collapsibleHookResult = useCollapsible({
unmountOnExit: false,
translateEnabled: false,
heightAnimation: true,
})
const getCollapsedLinesElm = useCallback(
({
tokens,
highlightProps,
}: {
tokens: Token[][]
highlightProps: HighlightProps
}) => {
if (!collapsedRange || !type) {
return <></>
}
const startIndex =
type === "start" ? collapsedRange.start - 1 : collapsedRange.start
const lines = tokens.slice(
startIndex,
Math.min(collapsedRange.end, tokens.length)
)
return (
<CodeBlockCollapsibleLines {...collapsibleHookResult} type={type}>
{getLines(lines, highlightProps, startIndex)}
</CodeBlockCollapsibleLines>
)
},
[collapsedRange, collapsibleHookResult]
)
const getNonCollapsedLinesElm = useCallback(
({
tokens,
highlightProps,
}: {
tokens: Token[][]
highlightProps: HighlightProps
}) => {
if (!collapsedRange) {
return getLines(tokens, highlightProps)
}
const isCollapseBeginning = collapsedRange.start === 1
const lines = tokens.slice(
isCollapseBeginning ? collapsedRange.end : 0,
isCollapseBeginning ? undefined : collapsedRange.start
)
return getLines(
lines,
highlightProps,
isCollapseBeginning ? collapsedRange.end : 0
)
},
[collapsedRange, collapsibleHookResult]
)
return {
getCollapsedLinesElm,
getNonCollapsedLinesElm,
type,
...collapsibleHookResult,
}
}

View File

@@ -0,0 +1,85 @@
"use client"
import React, { useState } from "react"
import { CSSTransition } from "react-transition-group"
export type CollapsibleProps = {
initialValue?: boolean
heightAnimation?: boolean
translateEnabled?: boolean
onClose?: () => void
unmountOnExit?: boolean
}
export type CollapsibleReturn = {
getCollapsibleElms: (children: React.ReactNode) => React.JSX.Element
collapsed: boolean
setCollapsed: React.Dispatch<React.SetStateAction<boolean>>
}
export const useCollapsible = ({
initialValue = true,
heightAnimation = false,
translateEnabled = true,
onClose,
unmountOnExit = true,
}: CollapsibleProps): CollapsibleReturn => {
const [collapsed, setCollapsed] = useState(initialValue)
const getCollapsibleElms = (children: React.ReactNode) => (
<CSSTransition
unmountOnExit={unmountOnExit}
in={!collapsed}
timeout={150}
onEnter={(node: HTMLElement) => {
if (heightAnimation) {
node.classList.add("transition-[height]")
node.style.height = `0px`
} else {
node.classList.add("!mb-docs_2", "!mt-0")
if (translateEnabled) {
node.classList.add("translate-y-docs_1", "transition-transform")
}
}
}}
onEntering={(node: HTMLElement) => {
if (heightAnimation) {
node.style.height = `${node.scrollHeight}px`
}
}}
onEntered={(node: HTMLElement) => {
if (heightAnimation) {
node.style.height = `auto`
}
}}
onExit={(node: HTMLElement) => {
if (heightAnimation) {
node.style.height = `${node.scrollHeight}px`
} else {
if (translateEnabled) {
node.classList.add("transition-transform", "!-translate-y-docs_1")
}
setTimeout(() => {
onClose?.()
}, 100)
}
}}
onExiting={(node: HTMLElement) => {
if (heightAnimation) {
node.style.height = `0px`
setTimeout(() => {
onClose?.()
}, 100)
}
}}
>
{children}
</CSSTransition>
)
return {
getCollapsibleElms,
collapsed,
setCollapsed,
}
}

View File

@@ -176,6 +176,11 @@ module.exports = {
top: "var(--docs-contrast-border-top)",
bot: "var(--docs-contrast-border-bot)",
},
// not in UI but necessary for show more button
button: {
DEFAULT: "#3D3D3F",
hover: "#505052",
},
},
},
/* docs defaults */
@@ -257,7 +262,13 @@ module.exports = {
},
backgroundImage: {
"code-fade-top-to-bottom": `linear-gradient(180deg, #27272A 0%, rgba(39, 39, 42, 0.00) 100%)`,
"code-fade-bottom-to-top": `linear-gradient(180deg, #27272A 0%, rgba(39, 39, 42, 0.00) 100%)`,
"code-fade-bottom-to-top": `linear-gradient(180deg, rgba(39, 39, 42, 0.00) 0%, #27272A 100%)`,
"base-code-fade-right-to-left": `linear-gradient(90deg, #18181b7d, #18181B)`,
"subtle-code-fade-right-to-left": `linear-gradient(90deg, #27272aa3, #27272A)`,
"code-fade-top-to-bottom-dark": `linear-gradient(180deg, #2F2F32 0%, rgba(47, 47, 50, 0.00) 100%)`,
"code-fade-bottom-to-top-dark": `linear-gradient(180deg, rgba(47, 47, 50, 0.00) 0%, #2F2F32 100%)`,
"base-code-fade-right-to-left-dark": `linear-gradient(90deg, #27272aa3, #27272A)`,
"subtle-code-fade-right-to-left-dark": `linear-gradient(90deg, #30303380, #303033)`,
},
screens: {
xs: "576px",

View File

@@ -196,7 +196,7 @@ const dark = {
"--docs-contrast-bg-base": "rgba(39, 39, 42, 1)",
"--docs-contrast-bg-base-pressed": "rgba(113, 113, 122, 1)",
"--docs-contrast-bg-base-hover": "rgba(82, 82, 91, 1)",
"--docs-contrast-bg-subtle": "rgba(255, 255, 255, 0.04)",
"--docs-contrast-bg-subtle": "rgba(47, 47, 50, 1)",
"--docs-contrast-bg-highlight": "rgba(82, 82, 91, 1)",
"--docs-contrast-bg-alpha": "rgba(63, 63, 70, 0.9)",
"--docs-contrast-fg-primary": "rgba(250, 250, 250, 1)",