From 4a6327e49731a5d27b1f9b5d28b3304ae76e65e6 Mon Sep 17 00:00:00 2001 From: Shahed Nasser Date: Wed, 5 Jun 2024 10:28:41 +0300 Subject: [PATCH] docs: make code blocks collapsible (#7606) * added collapsible code feature * fixed side shadow * fix build errors * change design * make code blocks collapsible --- .../api-routes/cors/page.mdx | 2 +- .../api-routes/protected-routes/page.mdx | 9 +- .../data-models/common-definitions/page.mdx | 2 +- .../data-models/soft-deletable/page.mdx | 2 +- .../data-payload/page.mdx | 6 +- .../loaders/outside-modules/page.mdx | 2 +- .../modules/module-relationships/page.mdx | 4 +- .../modules/remote-link/page.mdx | 21 ++- .../modules/remote-query/page.mdx | 4 +- .../modules/service-factory/page.mdx | 2 +- .../workflows/access-workflow-errors/page.mdx | 2 +- .../workflows/advanced-example/page.mdx | 6 +- .../workflows/compensation-function/page.mdx | 6 +- .../workflows/long-running-workflow/page.mdx | 4 +- .../workflows/parallel-steps/page.mdx | 2 +- .../workflows/retry-failed-steps/page.mdx | 2 +- .../workflows/workflow-timeout/page.mdx | 2 +- www/apps/book/app/basics/_services/page.mdx | 77 -------- .../notification/send-notification/page.mdx | 2 +- .../notification/sendgrid/page.mdx | 2 +- .../api-key/examples/page.mdx | 4 +- .../commerce-modules/auth/examples/page.mdx | 6 +- .../commerce-modules/cart/promotions/page.mdx | 4 +- .../order/promotion-adjustments/page.mdx | 4 +- .../pricing/examples/page.mdx | 2 +- www/apps/resources/app/js-client/page.mdx | 116 ++++++------ www/apps/resources/app/medusa-react/page.mdx | 40 ++--- .../cli-installation-errors/yarn-error.mdx | 41 ++--- .../module-x-error.mdx | 40 ++--- www/apps/resources/generated/files-map.mjs | 28 ++- www/apps/resources/generated/sidebar.mjs | 63 ++++--- www/apps/user-guide/providers/search.tsx | 7 +- .../components/CodeBlock/Actions/index.tsx | 136 ++++++++------ .../CodeBlock/Collapsible/Button/index.tsx | 57 ++++++ .../CodeBlock/Collapsible/Fade/index.tsx | 53 ++++++ .../CodeBlock/Collapsible/Lines/index.tsx | 29 +++ .../src/components/CodeBlock/Line/index.tsx | 5 +- .../src/components/CodeBlock/index.tsx | 168 ++++++++++++++---- .../docs-ui/src/components/Details/index.tsx | 61 ++----- www/packages/docs-ui/src/hooks/index.ts | 2 + .../use-collapsible-code-lines/index.tsx | 136 ++++++++++++++ .../src/hooks/use-collapsible/index.tsx | 85 +++++++++ www/packages/tailwind/base.tailwind.config.js | 13 +- www/packages/tailwind/theme-presets.js | 2 +- 44 files changed, 815 insertions(+), 446 deletions(-) delete mode 100644 www/apps/book/app/basics/_services/page.mdx create mode 100644 www/packages/docs-ui/src/components/CodeBlock/Collapsible/Button/index.tsx create mode 100644 www/packages/docs-ui/src/components/CodeBlock/Collapsible/Fade/index.tsx create mode 100644 www/packages/docs-ui/src/components/CodeBlock/Collapsible/Lines/index.tsx create mode 100644 www/packages/docs-ui/src/hooks/use-collapsible-code-lines/index.tsx create mode 100644 www/packages/docs-ui/src/hooks/use-collapsible/index.tsx diff --git a/www/apps/book/app/advanced-development/api-routes/cors/page.mdx b/www/apps/book/app/advanced-development/api-routes/cors/page.mdx index 2e3f78fbe2..514f0c1a14 100644 --- a/www/apps/book/app/advanced-development/api-routes/cors/page.mdx +++ b/www/apps/book/app/advanced-development/api-routes/cors/page.mdx @@ -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, diff --git a/www/apps/book/app/advanced-development/api-routes/protected-routes/page.mdx b/www/apps/book/app/advanced-development/api-routes/protected-routes/page.mdx index 42ff1038c3..ad1077fd4c 100644 --- a/www/apps/book/app/advanced-development/api-routes/protected-routes/page.mdx +++ b/www/apps/book/app/advanced-development/api-routes/protected-routes/page.mdx @@ -57,7 +57,7 @@ You can access the logged-in customer’s 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 user’s 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 don’t 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 = { diff --git a/www/apps/book/app/advanced-development/data-models/common-definitions/page.mdx b/www/apps/book/app/advanced-development/data-models/common-definitions/page.mdx index 82595bf89d..10be71e140 100644 --- a/www/apps/book/app/advanced-development/data-models/common-definitions/page.mdx +++ b/www/apps/book/app/advanced-development/data-models/common-definitions/page.mdx @@ -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, diff --git a/www/apps/book/app/advanced-development/data-models/soft-deletable/page.mdx b/www/apps/book/app/advanced-development/data-models/soft-deletable/page.mdx index dabf237728..a90d3f86e0 100644 --- a/www/apps/book/app/advanced-development/data-models/soft-deletable/page.mdx +++ b/www/apps/book/app/advanced-development/data-models/soft-deletable/page.mdx @@ -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" diff --git a/www/apps/book/app/advanced-development/events-and-subscribers/data-payload/page.mdx b/www/apps/book/app/advanced-development/events-and-subscribers/data-payload/page.mdx index 71fee4a8d7..ac8be48ab9 100644 --- a/www/apps/book/app/advanced-development/events-and-subscribers/data-payload/page.mdx +++ b/www/apps/book/app/advanced-development/events-and-subscribers/data-payload/page.mdx @@ -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({ diff --git a/www/apps/book/app/advanced-development/loaders/outside-modules/page.mdx b/www/apps/book/app/advanced-development/loaders/outside-modules/page.mdx index 006865d120..35fc6a5390 100644 --- a/www/apps/book/app/advanced-development/loaders/outside-modules/page.mdx +++ b/www/apps/book/app/advanced-development/loaders/outside-modules/page.mdx @@ -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" diff --git a/www/apps/book/app/advanced-development/modules/module-relationships/page.mdx b/www/apps/book/app/advanced-development/modules/module-relationships/page.mdx index 81e60699ea..8fb40efdf6 100644 --- a/www/apps/book/app/advanced-development/modules/module-relationships/page.mdx +++ b/www/apps/book/app/advanced-development/modules/module-relationships/page.mdx @@ -40,7 +40,7 @@ The Medusa application resolves these relationships while maintaining isolation Consider you’re 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 module’s 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" diff --git a/www/apps/book/app/advanced-development/modules/remote-link/page.mdx b/www/apps/book/app/advanced-development/modules/remote-link/page.mdx index 04b9f6bfdf..f23af8e0c8 100644 --- a/www/apps/book/app/advanced-development/modules/remote-link/page.mdx +++ b/www/apps/book/app/advanced-development/modules/remote-link/page.mdx @@ -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 { - const remoteLink: RemoteLink = req.scope.resolve( - ContainerRegistrationKeys.REMOTE_LINK - ) - - // ... + const remoteLink: RemoteLink = req.scope.resolve( + ContainerRegistrationKeys.REMOTE_LINK + ) + + // ... } ``` diff --git a/www/apps/book/app/advanced-development/modules/remote-query/page.mdx b/www/apps/book/app/advanced-development/modules/remote-query/page.mdx index f489ead610..e42356fb0a 100644 --- a/www/apps/book/app/advanced-development/modules/remote-query/page.mdx +++ b/www/apps/book/app/advanced-development/modules/remote-query/page.mdx @@ -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, diff --git a/www/apps/book/app/advanced-development/modules/service-factory/page.mdx b/www/apps/book/app/advanced-development/modules/service-factory/page.mdx index 54ff92147b..d00cd01937 100644 --- a/www/apps/book/app/advanced-development/modules/service-factory/page.mdx +++ b/www/apps/book/app/advanced-development/modules/service-factory/page.mdx @@ -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" diff --git a/www/apps/book/app/advanced-development/workflows/access-workflow-errors/page.mdx b/www/apps/book/app/advanced-development/workflows/access-workflow-errors/page.mdx index 0ff6503255..21dd64ce6d 100644 --- a/www/apps/book/app/advanced-development/workflows/access-workflow-errors/page.mdx +++ b/www/apps/book/app/advanced-development/workflows/access-workflow-errors/page.mdx @@ -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, diff --git a/www/apps/book/app/advanced-development/workflows/advanced-example/page.mdx b/www/apps/book/app/advanced-development/workflows/advanced-example/page.mdx index 3e00b5c6f1..590194e30b 100644 --- a/www/apps/book/app/advanced-development/workflows/advanced-example/page.mdx +++ b/www/apps/book/app/advanced-development/workflows/advanced-example/page.mdx @@ -46,7 +46,7 @@ export const updateProductHighlights = [ ["39", "", "Revert the product’s 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" diff --git a/www/apps/book/app/advanced-development/workflows/compensation-function/page.mdx b/www/apps/book/app/advanced-development/workflows/compensation-function/page.mdx index 220880152f..e4406c8ac5 100644 --- a/www/apps/book/app/advanced-development/workflows/compensation-function/page.mdx +++ b/www/apps/book/app/advanced-development/workflows/compensation-function/page.mdx @@ -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, diff --git a/www/apps/book/app/advanced-development/workflows/long-running-workflow/page.mdx b/www/apps/book/app/advanced-development/workflows/long-running-workflow/page.mdx index 9ab7e9fcc5..1cbda61c16 100644 --- a/www/apps/book/app/advanced-development/workflows/long-running-workflow/page.mdx +++ b/www/apps/book/app/advanced-development/workflows/long-running-workflow/page.mdx @@ -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, diff --git a/www/apps/book/app/advanced-development/workflows/parallel-steps/page.mdx b/www/apps/book/app/advanced-development/workflows/parallel-steps/page.mdx index d8cd4049d9..ab661c516a 100644 --- a/www/apps/book/app/advanced-development/workflows/parallel-steps/page.mdx +++ b/www/apps/book/app/advanced-development/workflows/parallel-steps/page.mdx @@ -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, diff --git a/www/apps/book/app/advanced-development/workflows/retry-failed-steps/page.mdx b/www/apps/book/app/advanced-development/workflows/retry-failed-steps/page.mdx index 9d03968600..91d0cbc924 100644 --- a/www/apps/book/app/advanced-development/workflows/retry-failed-steps/page.mdx +++ b/www/apps/book/app/advanced-development/workflows/retry-failed-steps/page.mdx @@ -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 step’s 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, diff --git a/www/apps/book/app/advanced-development/workflows/workflow-timeout/page.mdx b/www/apps/book/app/advanced-development/workflows/workflow-timeout/page.mdx index a8e8729972..b82c148b26 100644 --- a/www/apps/book/app/advanced-development/workflows/workflow-timeout/page.mdx +++ b/www/apps/book/app/advanced-development/workflows/workflow-timeout/page.mdx @@ -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, diff --git a/www/apps/book/app/basics/_services/page.mdx b/www/apps/book/app/basics/_services/page.mdx deleted file mode 100644 index 5cbac3023b..0000000000 --- a/www/apps/book/app/basics/_services/page.mdx +++ /dev/null @@ -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 -``` - - - -A service's file name must be the kebab-case name of the service without the word `Service`. - - - ---- - -## When to Use - - - -- 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. - - - ---- - -## 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 { - const [, count] = - await this.productModuleService.listAndCount() - - return `You have ${count} products` - } -} - -export default HelloWorldService -``` diff --git a/www/apps/resources/app/architectural-modules/notification/send-notification/page.mdx b/www/apps/resources/app/architectural-modules/notification/send-notification/page.mdx index 876b5ff7d2..c8f7498c90 100644 --- a/www/apps/resources/app/architectural-modules/notification/send-notification/page.mdx +++ b/www/apps/resources/app/architectural-modules/notification/send-notification/page.mdx @@ -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, diff --git a/www/apps/resources/app/architectural-modules/notification/sendgrid/page.mdx b/www/apps/resources/app/architectural-modules/notification/sendgrid/page.mdx index 75953065ab..5d7e6dc7bc 100644 --- a/www/apps/resources/app/architectural-modules/notification/sendgrid/page.mdx +++ b/www/apps/resources/app/architectural-modules/notification/sendgrid/page.mdx @@ -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, diff --git a/www/apps/resources/app/commerce-modules/api-key/examples/page.mdx b/www/apps/resources/app/commerce-modules/api-key/examples/page.mdx index 4b8ffe359f..64b61fa712 100644 --- a/www/apps/resources/app/commerce-modules/api-key/examples/page.mdx +++ b/www/apps/resources/app/commerce-modules/api-key/examples/page.mdx @@ -119,7 +119,7 @@ In this guide, you’ll find common examples of how you can use the API Key Modu - ```ts + ```ts collapsibleLines="1-9" expandButtonLabel="Show Imports" import { AuthenticatedMedusaRequest, MedusaResponse @@ -257,7 +257,7 @@ In this guide, you’ll find common examples of how you can use the API Key Modu - ```ts + ```ts collapsibleLines="1-8" expandButtonLabel="Show Imports" import { AuthenticatedMedusaRequest, MedusaResponse diff --git a/www/apps/resources/app/commerce-modules/auth/examples/page.mdx b/www/apps/resources/app/commerce-modules/auth/examples/page.mdx index d030701f84..3d27b69168 100644 --- a/www/apps/resources/app/commerce-modules/auth/examples/page.mdx +++ b/www/apps/resources/app/commerce-modules/auth/examples/page.mdx @@ -19,7 +19,7 @@ This example uses the [jsonwebtoken NPM package](https://www.npmjs.com/package/j - ```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 - ```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 - ```ts + ```ts collapsibleLines="1-7" expandButtonLabel="Show Imports" import { NextResponse } from "next/server" import { diff --git a/www/apps/resources/app/commerce-modules/cart/promotions/page.mdx b/www/apps/resources/app/commerce-modules/cart/promotions/page.mdx index c76a963908..7d25ac750c 100644 --- a/www/apps/resources/app/commerce-modules/cart/promotions/page.mdx +++ b/www/apps/resources/app/commerce-modules/cart/promotions/page.mdx @@ -41,7 +41,7 @@ Learn more about actions in the [Promotion Module’s documentation](../../promo -```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 cart’s line item and the shipping method’s adjustments. -```ts +```ts collapsibleLines="1-9" expandButtonLabel="Show Imports" import { AddItemAdjustmentAction, AddShippingMethodAdjustment, diff --git a/www/apps/resources/app/commerce-modules/order/promotion-adjustments/page.mdx b/www/apps/resources/app/commerce-modules/order/promotion-adjustments/page.mdx index c3902d3d04..6bfe6500de 100644 --- a/www/apps/resources/app/commerce-modules/order/promotion-adjustments/page.mdx +++ b/www/apps/resources/app/commerce-modules/order/promotion-adjustments/page.mdx @@ -41,7 +41,7 @@ Learn more about actions in the [Promotion Module’s documentation](../../promo -```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 order’s line items and the shipping method’s adjustments. -```ts +```ts collapsibleLines="1-9" expandButtonLabel="Show Imports" import { AddItemAdjustmentAction, AddShippingMethodAdjustment, diff --git a/www/apps/resources/app/commerce-modules/pricing/examples/page.mdx b/www/apps/resources/app/commerce-modules/pricing/examples/page.mdx index 0c664cedd5..a6f14f5c43 100644 --- a/www/apps/resources/app/commerce-modules/pricing/examples/page.mdx +++ b/www/apps/resources/app/commerce-modules/pricing/examples/page.mdx @@ -323,7 +323,7 @@ In this document, you’ll find common examples of how you can use the Pricing M - ```ts + ```ts collapsibleLines="1-8" expandButtonLabel="Show Imports" import { MedusaRequest, MedusaResponse } from "@medusajs/medusa" import { IPricingModuleService, diff --git a/www/apps/resources/app/js-client/page.mdx b/www/apps/resources/app/js-client/page.mdx index 7a261384b7..31dc29c19f 100644 --- a/www/apps/resources/app/js-client/page.mdx +++ b/www/apps/resources/app/js-client/page.mdx @@ -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: - + + + ```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 + ``` + + + + + ```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 + ``` + + + ### Cookie Session ID @@ -314,13 +312,11 @@ Once the user or customer is authenticated successfully, the Medusa client sets For example: - + + + ```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 + ``` + + + + + ```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 + ``` + + + ### 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): - + + + ```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 '/admin/users/' \\ + }) + ``` + + + + + ```bash + curl -L -X POST '/admin/users/' \\ -H 'Cookie: connect.sid={sid}' \\ -H 'Content-Type: application/json' \\ --data-raw '{ "api_token": "{api_token}" - }'` - } - } -]} group="client-type" /> + }' + ``` + + + Then, initialize the Medusa client passing it the `apiKey` option: diff --git a/www/apps/resources/app/medusa-react/page.mdx b/www/apps/resources/app/medusa-react/page.mdx index 10bea7f8a0..c36a226afe 100644 --- a/www/apps/resources/app/medusa-react/page.mdx +++ b/www/apps/resources/app/medusa-react/page.mdx @@ -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: - + + + ```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 + ``` + + + + + ```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 + ``` + + + ### Customer Authentication diff --git a/www/apps/resources/app/troubleshooting/_sections/cli-installation-errors/yarn-error.mdx b/www/apps/resources/app/troubleshooting/_sections/cli-installation-errors/yarn-error.mdx index 516846e607..a1a45ddf33 100644 --- a/www/apps/resources/app/troubleshooting/_sections/cli-installation-errors/yarn-error.mdx +++ b/www/apps/resources/app/troubleshooting/_sections/cli-installation-errors/yarn-error.mdx @@ -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 Yarn’s install location to the PATH variable: - + + + ```plain + export PATH="$(yarn global bin):$PATH + ``` + + + + + ```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 + ``` + + + You can learn more in [Yarn’s documentation](https://classic.yarnpkg.com/en/docs/cli/global#adding-the-install-location-to-your-path). \ No newline at end of file diff --git a/www/apps/resources/app/troubleshooting/_sections/common-installation-errors/module-x-error.mdx b/www/apps/resources/app/troubleshooting/_sections/common-installation-errors/module-x-error.mdx index 93848da537..625a124768 100644 --- a/www/apps/resources/app/troubleshooting/_sections/common-installation-errors/module-x-error.mdx +++ b/www/apps/resources/app/troubleshooting/_sections/common-installation-errors/module-x-error.mdx @@ -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: - + + + + ```bash + rm -rf node_modules + yarn install + ``` + + + + + ```bash + rd /s /q node_modules + yarn install + ``` + + + \ No newline at end of file diff --git a/www/apps/resources/generated/files-map.mjs b/www/apps/resources/generated/files-map.mjs index 0f91de8f5d..7cbdcec1ef 100644 --- a/www/apps/resources/generated/files-map.mjs +++ b/www/apps/resources/generated/files-map.mjs @@ -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" diff --git a/www/apps/resources/generated/sidebar.mjs b/www/apps/resources/generated/sidebar.mjs index 2c7fcc0c6d..9fac9bdb6d 100644 --- a/www/apps/resources/generated/sidebar.mjs +++ b/www/apps/resources/generated/sidebar.mjs @@ -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": [] - } - ] } ] } diff --git a/www/apps/user-guide/providers/search.tsx b/www/apps/user-guide/providers/search.tsx index 0e78a7c064..fca080eac7 100644 --- a/www/apps/user-guide/providers/search.tsx +++ b/www/apps/user-guide/providers/search.tsx @@ -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: , + icon: , component: ( { ), title: "AI Assistant", badge: { - variant: "purple", + variant: "blue", children: "Beta", + badgeType: "shaded", }, }, ]} diff --git a/www/packages/docs-ui/src/components/CodeBlock/Actions/index.tsx b/www/packages/docs-ui/src/components/CodeBlock/Actions/index.tsx index 40a496b90d..8086dffb07 100644 --- a/www/packages/docs-ui/src/components/CodeBlock/Actions/index.tsx +++ b/www/packages/docs-ui/src/components/CodeBlock/Actions/index.tsx @@ -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> @@ -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 ( ) } diff --git a/www/packages/docs-ui/src/components/CodeBlock/Collapsible/Button/index.tsx b/www/packages/docs-ui/src/components/CodeBlock/Collapsible/Button/index.tsx new file mode 100644 index 0000000000..7d56b49a45 --- /dev/null +++ b/www/packages/docs-ui/src/components/CodeBlock/Collapsible/Button/index.tsx @@ -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 + +export const CodeBlockCollapsibleButton = ({ + type, + expandButtonLabel = "Show more", + collapsed, + setCollapsed, + className, +}: CodeBlockCollapsibleButtonProps) => { + if (!collapsed) { + return <> + } + + return ( + <> + {type === "start" && ( + + )} + {type === "end" && ( + + )} + + ) +} diff --git a/www/packages/docs-ui/src/components/CodeBlock/Collapsible/Fade/index.tsx b/www/packages/docs-ui/src/components/CodeBlock/Collapsible/Fade/index.tsx new file mode 100644 index 0000000000..199d5caeff --- /dev/null +++ b/www/packages/docs-ui/src/components/CodeBlock/Collapsible/Fade/index.tsx @@ -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 + +export const CodeBlockCollapsibleFade = ({ + type, + hasHeader = false, + collapsed, +}: CodeBlockCollapsibleFadeProps) => { + if (!collapsed) { + return <> + } + + return ( + + {type === "end" && ( + + )} + {type === "start" && ( + + )} + + ) +} diff --git a/www/packages/docs-ui/src/components/CodeBlock/Collapsible/Lines/index.tsx b/www/packages/docs-ui/src/components/CodeBlock/Collapsible/Lines/index.tsx new file mode 100644 index 0000000000..809e37f44c --- /dev/null +++ b/www/packages/docs-ui/src/components/CodeBlock/Collapsible/Lines/index.tsx @@ -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 + +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) +} diff --git a/www/packages/docs-ui/src/components/CodeBlock/Line/index.tsx b/www/packages/docs-ui/src/components/CodeBlock/Line/index.tsx index d02b2a7898..7a29e37718 100644 --- a/www/packages/docs-ui/src/components/CodeBlock/Line/index.tsx +++ b/www/packages/docs-ui/src/components/CodeBlock/Line/index.tsx @@ -22,6 +22,7 @@ type CodeBlockLineProps = { lineNumber: number showLineNumber: boolean lineNumberColorClassName: string + lineNumberBgClassName: string noLineNumbers?: boolean } & Pick @@ -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} diff --git a/www/packages/docs-ui/src/components/CodeBlock/index.tsx b/www/packages/docs-ui/src/components/CodeBlock/index.tsx index a103b65115..6061d953ae 100644 --- a/www/packages/docs-ui/src/components/CodeBlock/index.tsx +++ b/www/packages/docs-ui/src/components/CodeBlock/index.tsx @@ -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(null) + const codeRef = useRef(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 = { - 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 ( + 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 = 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 }) => ( -
+
+ {collapsibleType === "start" && ( + <> + + + + )}
 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 (
-                         1}
-                          key={i}
-                          lineNumberColorClassName={lineNumbersColor}
-                          {...rest}
-                        />
-                      )
+                    {collapsibleType === "start" &&
+                      getCollapsedLinesElm({
+                        tokens,
+                        highlightProps: rest,
+                      })}
+                    {getNonCollapsedLinesElm({
+                      tokens,
+                      highlightProps: rest,
                     })}
+                    {collapsibleType === "end" &&
+                      getCollapsedLinesElm({
+                        tokens,
+                        highlightProps: rest,
+                      })}
                   
                 
{!title && ( @@ -280,6 +369,21 @@ export const CodeBlock = ({ isSingleLine={tokens.length <= 1} /> )} + {collapsibleType === "end" && ( + <> + + + + )}
)} diff --git a/www/packages/docs-ui/src/components/Details/index.tsx b/www/packages/docs-ui/src/components/Details/index.tsx index 985b057f7d..e528ac5f34 100644 --- a/www/packages/docs-ui/src/components/Details/index.tsx +++ b/www/packages/docs-ui/src/components/Details/index.tsx @@ -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(null) const handleToggle = (e: React.MouseEvent) => { @@ -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, })} - { - 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( }> {children} - + )} ) } diff --git a/www/packages/docs-ui/src/hooks/index.ts b/www/packages/docs-ui/src/hooks/index.ts index 32ae50ecb7..e9850717ba 100644 --- a/www/packages/docs-ui/src/hooks/index.ts +++ b/www/packages/docs-ui/src/hooks/index.ts @@ -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" diff --git a/www/packages/docs-ui/src/hooks/use-collapsible-code-lines/index.tsx b/www/packages/docs-ui/src/hooks/use-collapsible-code-lines/index.tsx new file mode 100644 index 0000000000..dfb43966fd --- /dev/null +++ b/www/packages/docs-ui/src/hooks/use-collapsible-code-lines/index.tsx @@ -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 ( + + {getLines(lines, highlightProps, startIndex)} + + ) + }, + [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, + } +} diff --git a/www/packages/docs-ui/src/hooks/use-collapsible/index.tsx b/www/packages/docs-ui/src/hooks/use-collapsible/index.tsx new file mode 100644 index 0000000000..c3d5b45373 --- /dev/null +++ b/www/packages/docs-ui/src/hooks/use-collapsible/index.tsx @@ -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> +} + +export const useCollapsible = ({ + initialValue = true, + heightAnimation = false, + translateEnabled = true, + onClose, + unmountOnExit = true, +}: CollapsibleProps): CollapsibleReturn => { + const [collapsed, setCollapsed] = useState(initialValue) + + const getCollapsibleElms = (children: React.ReactNode) => ( + { + 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} + + ) + + return { + getCollapsibleElms, + collapsed, + setCollapsed, + } +} diff --git a/www/packages/tailwind/base.tailwind.config.js b/www/packages/tailwind/base.tailwind.config.js index b557ad96e0..de32c117ec 100644 --- a/www/packages/tailwind/base.tailwind.config.js +++ b/www/packages/tailwind/base.tailwind.config.js @@ -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", diff --git a/www/packages/tailwind/theme-presets.js b/www/packages/tailwind/theme-presets.js index 633eb76ffc..77aa118506 100644 --- a/www/packages/tailwind/theme-presets.js +++ b/www/packages/tailwind/theme-presets.js @@ -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)",