diff --git a/src/layouts/sidebar/DocsNavMenu.astro b/src/layouts/sidebar/DocsNavMenu.astro index 01fb0a1fe..1849c65bb 100644 --- a/src/layouts/sidebar/DocsNavMenu.astro +++ b/src/layouts/sidebar/DocsNavMenu.astro @@ -89,7 +89,7 @@ const serverSystemVersion = readServerSystemVersion(); ); } - if (item.slug === "===") { + if (item.path === "===") { return (

  • diff --git a/src/layouts/sidebar/LeftSidebarItem.tsx b/src/layouts/sidebar/LeftSidebarItem.tsx index eac027e0d..b1fbcddb0 100644 --- a/src/layouts/sidebar/LeftSidebarItem.tsx +++ b/src/layouts/sidebar/LeftSidebarItem.tsx @@ -8,14 +8,21 @@ import type { SystemVersion } from "~/type"; function LeftSidebarItem(props: NavMenuPage) { const systemVersion = useSystemVersion(); if (props.items.length > 0) return ; - const { title, slug } = props; + const { title, path } = props; const pageSlug = slugSignal.value; - const isActive = pageSlug === slug; - const href = `/docs${slug}`; + const isActive = pageSlug === path; + const [href, isExternal] = (() => { + try { + return [new URL(path).toString(), true]; + } catch (e) { + return [`/docs${path}`, false]; + } + })(); return ( @@ -23,11 +30,11 @@ function LeftSidebarItem(props: NavMenuPage) { } export default LeftSidebarItem; -function FolderLink({ title, slug, items, systemVersion }: NavMenuPage) { - const openSignal = useComputed(() => !!navOpenStatesSignal.value[slug]); +function FolderLink({ title, path, items, systemVersion }: NavMenuPage) { + const openSignal = useComputed(() => !!navOpenStatesSignal.value[path]); const open = openSignal.value; const pageSlug = slugSignal.value; - const isActive = pageSlug === slug; + const isActive = pageSlug === path; return (
    { navOpenStatesSignal.value = { ...navOpenStatesSignal.value, - [slug]: !open, + [path]: !open, }; }} > @@ -63,7 +70,7 @@ function FolderLink({ title, slug, items, systemVersion }: NavMenuPage) {
      {items.map((item) => ( -
    • +
    • ))} @@ -76,6 +83,7 @@ function FolderLink({ title, slug, items, systemVersion }: NavMenuPage) { export interface JustLinkProps { title: string; href: string; + isExternal?: boolean; isActive: boolean; systemVersion?: SystemVersion | undefined; event?: { @@ -86,6 +94,7 @@ export interface JustLinkProps { export function JustLink({ title, href, + isExternal, isActive, systemVersion, event, @@ -93,12 +102,13 @@ export function JustLink({ return (
      event && trackEvent(event.name, event.props)} + target={isExternal ? "_blank" : "_self"} > - + ); } @@ -113,11 +123,15 @@ export function getLinkStyle(isActive: boolean): string { interface LinkTitleProps { title: string; + isExternal?: boolean | undefined; } -function LinkTitle({ title }: LinkTitleProps) { +function LinkTitle({ title, isExternal }: LinkTitleProps) { return ( - + {title || (unknown page)} + {isExternal && ( + + )} ); } diff --git a/src/state/server-only/nav.ts b/src/state/server-only/nav.ts index a41d36941..6608b3179 100644 --- a/src/state/server-only/nav.ts +++ b/src/state/server-only/nav.ts @@ -28,7 +28,7 @@ export interface NavMenu { export type NavMenuItem = NavMenuPage | NavMenuGroup; export interface NavMenuPage { type: "page"; - slug: string; + path: string; title: string; items: NavMenuPage[]; systemVersion?: SystemVersion | undefined; @@ -50,15 +50,15 @@ export const navMenuItemsKo = toNavMenuItems( export const navMenu = { en: navMenuItemsEn, ko: navMenuItemsKo }; export interface NavMenuSystemVersions { - [slug: string]: SystemVersion; + [path: string]: SystemVersion; } export function calcNavMenuSystemVersions( navMenuItems: NavMenuItem[], ): NavMenuSystemVersions { const result: NavMenuSystemVersions = {}; for (const item of iterNavMenuItems(navMenuItems)) { - if (!("slug" in item)) continue; - if (item.systemVersion) result[item.slug] = item.systemVersion; + if (!("path" in item)) continue; + if (item.systemVersion) result[item.path] = item.systemVersion; } return result; } @@ -84,7 +84,7 @@ function* iterNavMenuAncestors( if (item.type === "group") { yield* iterNavMenuAncestors(item.items, ancestors); } else if (item.type === "page") { - const { slug, items } = item; + const { path: slug, items } = item; yield { slug, ancestors }; yield* iterNavMenuAncestors(items, [...ancestors, slug]); } @@ -107,7 +107,7 @@ function toNavMenuItems( if (typeof item === "string") { return { type: "page", - slug: item, + path: item, title: frontmatters[item]?.["title"] || "", items: [], systemVersion, @@ -116,7 +116,7 @@ function toNavMenuItems( const _systemVersion = item.systemVersion || systemVersion; return { type: "page", - slug: item.slug, + path: item.slug, title: frontmatters[item.slug]?.["title"] || "", items: item.items ? (toNavMenuItems( @@ -127,6 +127,21 @@ function toNavMenuItems( : [], systemVersion: _systemVersion, }; + } else if ("href" in item) { + const _systemVersion = item.systemVersion || systemVersion; + return { + type: "page", + path: item.href, + title: item.label, + items: item.items + ? (toNavMenuItems( + item.items, + frontmatters, + _systemVersion, + ) as NavMenuPage[]) + : [], + systemVersion: _systemVersion, + }; } else { const _systemVersion = item.systemVersion || systemVersion; return { diff --git a/src/type.ts b/src/type.ts index e8efde501..748ffc49f 100644 --- a/src/type.ts +++ b/src/type.ts @@ -12,14 +12,24 @@ export type SystemVersion = z.infer; export type YamlNavMenuToplevelItem = | YamlNavMenuPageSugar | YamlNavMenuPage + | YamlNavMenuExternalPage | YamlNavMenuGroup; -export type YamlNavMenuItem = YamlNavMenuPageSugar | YamlNavMenuPage; +export type YamlNavMenuItem = + | YamlNavMenuPageSugar + | YamlNavMenuPage + | YamlNavMenuExternalPage; type YamlNavMenuPageSugar = string; interface YamlNavMenuPage { slug: string; items: YamlNavMenuItem[]; systemVersion?: SystemVersion; } +interface YamlNavMenuExternalPage { + label: string; + href: string; + items?: YamlNavMenuItem[]; + systemVersion?: SystemVersion; +} interface YamlNavMenuGroup { label: string; items: YamlNavMenuItem[];