diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 3c4e7f1d0..820a640b0 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,4 +1,4 @@ -* @vinckr @aeneasr @zepatrik @piotrmsc @unatasha8 +* @vinckr @aeneasr @zepatrik @piotrmsc @unatasha8 @wassimoo *.md @vinckr @aeneasr @unatasha8 *.mdx @vinckr @aeneasr @unatasha8 -/code-examples/ @aeneasr @zepatrik @piotrmsc +/code-examples/ @aeneasr @zepatrik @piotrmsc @wassimoo diff --git a/AGENTS.md b/AGENTS.md index 1090222d4..ccd4e0ac7 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -38,7 +38,7 @@ OR ### Shared Source Content -- Location: `/src/components/shared//...` +- Location: `/src/components/Shared//...` - Purpose: - Reusable, deployment-agnostic content - Written once, used across deployments @@ -53,7 +53,7 @@ Locations: Shell files: -- Import content from `/src/components/shared/...` +- Import content from `/src/components/Shared/...` - Represent a page for a specific deployment - Are the files added to sidebars @@ -101,12 +101,12 @@ If content is specific to **self-hosted (OEL/OSS)**: **OEL is canonical** ### 2. Update content -- Edit shared source when possible:`/src/components/shared//...` +- Edit shared source when possible: `/src/components/Shared//...` - Avoid duplicating content across deployments **Example (shared source):** -`/src/components/shared/kratos/index.mdx` +`/src/components/Shared/kratos/index.mdx` ```mdx Ory Kratos Identities is an API-first identity and user management system... @@ -141,7 +141,7 @@ sidebar_label: Introduction -import MyPartial from "@site/src/components/shared/kratos/index.mdx" +import MyPartial from "@site/src/components/Shared/kratos/index.mdx" ``` @@ -174,7 +174,7 @@ import MyPartial from "@site/src/components/shared/kratos/index.mdx" ### Summary -- Edit → `/src/components/shared/...` +- Edit → `/src/components/Shared/...` - Expose → `docs//...` shell files - Navigate → via sidebars - De-duplicate → with canonical URLs @@ -190,5 +190,34 @@ import MyPartial from "@site/src/components/shared/kratos/index.mdx" ## When in Doubt - Check the sidebar first -- Look for `/src/components/shared/...` usage +- Look for `/src/components/Shared/...` usage - If unclear, ask the Docs team before making structural changes + +## MDX paths, imports, and internal links + +- **Use `@site` for imports (not links)**: use `@site/...` when importing + snippets/partials (for example `@site/src/components/Shared/...`) to avoid + brittle relative import paths. Do not use `@site` as a way to “link” to docs + pages. +- **Don’t link to shared partials**: shared files in `src/components/Shared/...` + are implementation details; link to the deployment shell page(s) in + `docs//...` instead. +- **Use `SameDeploymentLink` when linking across deployments**: if a doc exists + under `docs/network/...`, `docs/oel/...`, and `docs/oss/...`, use + `SameDeploymentLink` so readers stay on their current deployment. In this repo + it’s registered globally via `src/theme/MDXComponents.js`, so you can use it + in MDX without importing it. + +Example: + +```mdx + + Ory Kratos introduction + + +{/* Optional per-deployment overrides */} + + + Kratos intro (deployment-aware) + +``` diff --git a/src/components/SameDeploymentLink.tsx b/src/components/SameDeploymentLink.tsx new file mode 100644 index 000000000..e52d9cdda --- /dev/null +++ b/src/components/SameDeploymentLink.tsx @@ -0,0 +1,78 @@ +import React, { useEffect, type ReactNode } from "react" +import Link from "@docusaurus/Link" +import { useLocation } from "@docusaurus/router" +import { useAllDocsData } from "@docusaurus/plugin-content-docs/client" + +type DocsDeploymentSegment = "network" | "oel" | "oss" + +type SameDeploymentLinkProps = { + to: string + // Optional overrides for the link target based on the deployment segment + network?: string + oel?: string + oss?: string + children: ReactNode +} + +const DEFAULT_DOCS_PLUGIN_ID = "default" + +const DEPLOYMENT_SEGMENT_PATTERN = /\/(network|oel|oss)(?:\/|$)/ + +const stripLeadingSlashes = (value: string) => value.replace(/^\/+/, "") +const normalizePath = (value: string) => `/${stripLeadingSlashes(value)}` + +/** + * Internal docs link that keeps the reader on the current deployment (Network / OEL / OSS). + */ +export default function SameDeploymentLink({ + to, + network, + oel, + oss, + children, +}: SameDeploymentLinkProps): JSX.Element { + const { pathname } = useLocation() + const segment = + (pathname.match(DEPLOYMENT_SEGMENT_PATTERN)?.[1] as + | DocsDeploymentSegment + | undefined) ?? "network" + + const rewriteToCurrentDeployment = (value: string): string => { + const path = normalizePath(value) + const match = path.match(DEPLOYMENT_SEGMENT_PATTERN) + if (match) { + // Replace explicit deployment segment with the current one. + return path.replace(DEPLOYMENT_SEGMENT_PATTERN, `/${segment}/`) + } + // Prefix when no deployment segment is present. + return `/${segment}${path}` + } + + const overrideForCurrentDeployment = { network, oel, oss }[segment] + const href = overrideForCurrentDeployment + ? normalizePath(overrideForCurrentDeployment) + : rewriteToCurrentDeployment(to) + const allDocs = useAllDocsData() + + useEffect(() => { + if (!DEPLOYMENT_SEGMENT_PATTERN.test(href)) return + const plugin = allDocs[DEFAULT_DOCS_PLUGIN_ID] + const version = + plugin?.versions.find((v) => v.isLast) ?? plugin?.versions[0] + if (!version?.docs?.length) return + + const docId = stripLeadingSlashes(href) + const found = version.docs.some((d) => d.id === docId) + if (!found) { + const overrideMsg = overrideForCurrentDeployment + ? ` (override prop "${segment}" was used)` + : "" + console.warn( + `[SameDeploymentLink] No doc with id "${docId}". ` + + `Resolved href="${href}" from to="${to}" under deployment "${segment}" did not match any page in this build${overrideMsg}.`, + ) + } + }, [allDocs, href, overrideForCurrentDeployment, segment, to]) + + return {children} +} diff --git a/src/components/Shared/kratos/index.mdx b/src/components/Shared/kratos/index.mdx index 42e042557..530a10ade 100644 --- a/src/components/Shared/kratos/index.mdx +++ b/src/components/Shared/kratos/index.mdx @@ -24,8 +24,8 @@ modern software applications have to deal with: Ory Identities calls user accounts "identities". The terms "user accounts", "users", and "identities" are used interchangeably in the Ory documentation. -Read [more here](../../../../docs/network/kratos/quickstarts/identity-model) to -learn more about identities in Ory. +Read more +here to learn more about identities in Ory. ::: diff --git a/src/contexts/QuickstartsDeploymentContext.tsx b/src/contexts/QuickstartsDeploymentContext.tsx index 3efd68925..9c1f1bcf9 100644 --- a/src/contexts/QuickstartsDeploymentContext.tsx +++ b/src/contexts/QuickstartsDeploymentContext.tsx @@ -1,4 +1,10 @@ -import React, { createContext, useContext, useState, useCallback } from "react" +import React, { + createContext, + useContext, + useState, + useCallback, + useEffect, +} from "react" export type QuickstartsDeploymentId = "network" | "oel" | "oss" @@ -19,6 +25,13 @@ export function QuickstartsDeploymentProvider({ }) { const [deployment, setDeploymentState] = useState(initialDeployment) + + // Keep context in sync with explicitly segmented URLs (e.g. /docs/oel/...). + useEffect(() => { + if (initialDeployment === "network") return + setDeploymentState(initialDeployment) + }, [initialDeployment]) + const setDeployment = useCallback((id: QuickstartsDeploymentId) => { setDeploymentState(id) }, []) diff --git a/src/theme/DocRoot/index.js b/src/theme/DocRoot/index.js index bcff5a4b8..55afef7c7 100644 --- a/src/theme/DocRoot/index.js +++ b/src/theme/DocRoot/index.js @@ -15,6 +15,7 @@ import { QuickstartsDeploymentProvider, useQuickstartsDeployment, } from "@site/src/contexts/QuickstartsDeploymentContext" +import { docsDeploymentFromPathname } from "@site/src/utils/docsDeploymentFromPathname" const QUICKSTARTS_SIDEBAR = "quickstartsSidebar" @@ -79,13 +80,14 @@ export default function DocRootWrapper(props) { } const { docElement, sidebarName, sidebarItems } = currentDocRouteMetadata const pathname = props.location?.pathname ?? "" + const deploymentFromPath = docsDeploymentFromPathname(pathname) const versionMetadata = useDocsVersion() ?? {} const docsSidebars = versionMetadata.docsSidebars ?? {} return (
- +