From f9c0a7da312953f2710de8cd60c12c147689e2b4 Mon Sep 17 00:00:00 2001 From: Vordgi Date: Fri, 18 Oct 2024 21:59:11 +0400 Subject: [PATCH 1/2] rd-356 external mark in header and sidebar links --- .../src/components/blocks/nav-link/index.tsx | 12 +++++-- .../elements/sidebar/sidebar-link/index.tsx | 1 + .../src/components/ui/content-link/index.tsx | 10 +++--- .../ui/external-mark/external-mark.scss | 31 ++++++++++++++++ .../src/components/ui/external-mark/index.tsx | 10 ++++++ .../src/core/utils/parse-structure.ts | 36 ++++++++++--------- .../robindoc/src/core/utils/path-tools.ts | 9 +++++ 7 files changed, 84 insertions(+), 25 deletions(-) create mode 100644 packages/robindoc/src/components/ui/external-mark/external-mark.scss create mode 100644 packages/robindoc/src/components/ui/external-mark/index.tsx diff --git a/packages/robindoc/src/components/blocks/nav-link/index.tsx b/packages/robindoc/src/components/blocks/nav-link/index.tsx index 568cb2ae..ab2ecb56 100644 --- a/packages/robindoc/src/components/blocks/nav-link/index.tsx +++ b/packages/robindoc/src/components/blocks/nav-link/index.tsx @@ -6,6 +6,8 @@ import { usePathname } from "next/navigation"; import clsx from "clsx"; import { useNavigate } from "@src/components/contexts/navigate/use-navigate"; +import { ExternalMark } from "@src/components/ui/external-mark"; +import { checkIsLinkExternal } from "@src/core/utils/path-tools"; type NavLinkProps = React.AnchorHTMLAttributes & React.PropsWithChildren & { @@ -14,7 +16,7 @@ type NavLinkProps = React.AnchorHTMLAttributes & }; export const NavLink = forwardRef( - ({ onClick, className, href, targetClassName, activeClassName, ...props }, ref) => { + ({ onClick, className, href, targetClassName, activeClassName, children, ...props }, ref) => { const { listeners } = useNavigate(); const pathname = usePathname(); @@ -22,6 +24,8 @@ export const NavLink = forwardRef( [...listeners].forEach((el) => el.listener()); if (onClick) onClick(e); }; + const isLinkExternal = checkIsLinkExternal(href); + const additionalProps = isLinkExternal ? { target: "_blank", rel: "noopener noreferrer" } : {}; return ( ( )} ref={ref} onClick={clickHandler} + {...additionalProps} {...props} - /> + > + {children} + {isLinkExternal && } + ); }, ); diff --git a/packages/robindoc/src/components/elements/sidebar/sidebar-link/index.tsx b/packages/robindoc/src/components/elements/sidebar/sidebar-link/index.tsx index 061588bb..6206861b 100644 --- a/packages/robindoc/src/components/elements/sidebar/sidebar-link/index.tsx +++ b/packages/robindoc/src/components/elements/sidebar/sidebar-link/index.tsx @@ -5,6 +5,7 @@ import { usePathname } from "next/navigation"; import clsx from "clsx"; import { NavLink } from "@src/components/blocks/nav-link"; + import { type TreeItem } from "../types"; import { checkIsTargetPathname, collectItems } from "../tools"; diff --git a/packages/robindoc/src/components/ui/content-link/index.tsx b/packages/robindoc/src/components/ui/content-link/index.tsx index d9861c87..6ad34f09 100644 --- a/packages/robindoc/src/components/ui/content-link/index.tsx +++ b/packages/robindoc/src/components/ui/content-link/index.tsx @@ -2,6 +2,8 @@ import React from "react"; import Link, { type LinkProps } from "next/link"; import clsx from "clsx"; +import { ExternalMark } from "../external-mark"; + import "./content-link.scss"; export interface ContentLinkProps @@ -12,15 +14,11 @@ export interface ContentLinkProps export const ContentLink: React.FC = ({ className, external, children, ...props }) => { const additionalProps = external ? { target: "_blank", rel: "noopener noreferrer" } : {}; + return ( {children} - {external && ( - <> -   - - - )} + {external && } ); }; diff --git a/packages/robindoc/src/components/ui/external-mark/external-mark.scss b/packages/robindoc/src/components/ui/external-mark/external-mark.scss new file mode 100644 index 00000000..cf719eb5 --- /dev/null +++ b/packages/robindoc/src/components/ui/external-mark/external-mark.scss @@ -0,0 +1,31 @@ +.r-external-mark { + position: relative; + vertical-align: text-top; + display: inline-block; + margin-left: -4px; + margin-right: 2px; + width: 6px; + height: 6px; + + &::after { + content: ""; + position: absolute; + top: 0; + right: 0; + width: 100%; + height: 100%; + border-top: 1px solid currentColor; + border-right: 1px solid currentColor; + } + + &::before { + content: ""; + position: absolute; + top: 0; + right: 0; + width: 3px; + height: 3px; + background-color: currentColor; + border-radius: 0 0 0 4px; + } +} diff --git a/packages/robindoc/src/components/ui/external-mark/index.tsx b/packages/robindoc/src/components/ui/external-mark/index.tsx new file mode 100644 index 00000000..b0c0ca24 --- /dev/null +++ b/packages/robindoc/src/components/ui/external-mark/index.tsx @@ -0,0 +1,10 @@ +import React from "react"; + +import "./external-mark.scss"; + +export const ExternalMark = () => ( + <> +   + + +); diff --git a/packages/robindoc/src/core/utils/parse-structure.ts b/packages/robindoc/src/core/utils/parse-structure.ts index 245b38a9..d353bacb 100644 --- a/packages/robindoc/src/core/utils/parse-structure.ts +++ b/packages/robindoc/src/core/utils/parse-structure.ts @@ -3,7 +3,7 @@ import { type Pages, type Crumbs, type Configuration } from "../types/content"; import { type TreeItem } from "../../components/elements/sidebar/types"; import { getConfiguration } from "./get-configuration"; import { getMeta } from "./get-meta"; -import { generatePseudoTitle, normalizePathname } from "./path-tools"; +import { generatePseudoTitle, checkIsLinkExternal, mergePathname, normalizePathname } from "./path-tools"; import { loadContent } from "./load-content"; const parseJSONStructure = async ( @@ -28,21 +28,23 @@ const parseJSONStructure = async ( const clientPath = normalizePathname( segment === "index" ? parentPathname : parentPathname + "/" + segment, ); - const pathname = (parentConfiguration.basePath || "") + clientPath; + const pathname = mergePathname(parentConfiguration.basePath, clientPath); const pathnameNormalized = normalizePathname(pathname); - const origPath = await parentConfiguration.provider?.getPageSourcePathname( - clientPath, - pathnameNormalized, - ); - if (origPath) { - pages[pathnameNormalized] = { - title: data.title, - uri: clientPath, - configuration: parentConfiguration, - origPath, - crumbs, - }; + if (!checkIsLinkExternal(pathnameNormalized)) { + const origPath = await parentConfiguration.provider?.getPageSourcePathname( + clientPath, + pathnameNormalized, + ); + if (origPath) { + pages[pathnameNormalized] = { + title: data.title, + uri: clientPath, + configuration: parentConfiguration, + origPath, + crumbs, + }; + } } let subTree: TreeItem[] | undefined; @@ -109,7 +111,7 @@ const parseAutoStructure = async ( } const { clientPath } = generatedItem; - const pathname = (parentConfiguration.basePath || "") + clientPath; + const pathname = mergePathname(parentConfiguration.basePath, clientPath); const pathnameNormalized = normalizePathname(pathname); const meta = await getMeta({ provider: parentConfiguration.provider, uri: clientPath }); @@ -178,10 +180,10 @@ const parseStaticStructure = async ( let subCrumbs = crumbs; const configuration = getConfiguration(item.configuration || {}, parentConfiguration); const clientPath = item.href; - const pathname = clientPath && configuration.basePath ? configuration.basePath + clientPath : clientPath; + const pathname = mergePathname(configuration.basePath, clientPath); const pathnameNormalized = normalizePathname(pathname); - if (clientPath) { + if (!checkIsLinkExternal(pathnameNormalized) && clientPath) { const origPath = await configuration.provider?.getPageSourcePathname(clientPath, pathnameNormalized); if (origPath) { diff --git a/packages/robindoc/src/core/utils/path-tools.ts b/packages/robindoc/src/core/utils/path-tools.ts index 97687ff4..2716344d 100644 --- a/packages/robindoc/src/core/utils/path-tools.ts +++ b/packages/robindoc/src/core/utils/path-tools.ts @@ -22,3 +22,12 @@ export const generatePseudoTitle = (path?: string | null) => { const lastSegmentWords = lastSegment.split("-"); return lastSegmentWords.map((word) => word[0].toUpperCase() + word.substring(1)).join(" "); }; + +export const checkIsLinkExternal = (href: string) => { + const url = new URL(href, "http://r"); + return url.host !== "r"; +}; + +export const mergePathname = (basePath?: string, href?: string) => { + return !href || checkIsLinkExternal(href) ? href : (basePath || "") + href; +}; From aad300ea0cb83517fc4315d39d86120f4b570985 Mon Sep 17 00:00:00 2001 From: Vordgi Date: Fri, 18 Oct 2024 21:59:36 +0400 Subject: [PATCH 2/2] rd-356 release 2.2.1 --- packages/robindoc/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/robindoc/package.json b/packages/robindoc/package.json index 49d4a3ce..bc4bc607 100644 --- a/packages/robindoc/package.json +++ b/packages/robindoc/package.json @@ -1,6 +1,6 @@ { "name": "robindoc", - "version": "2.2.0", + "version": "2.2.1", "description": "", "main": "./lib/index.js", "scripts": {