mirror of
https://github.com/goauthentik/authentik
synced 2026-04-27 18:07:15 +02:00
112 lines
3.9 KiB
TypeScript
112 lines
3.9 KiB
TypeScript
// Shared utilities and types
|
|
import { type GlossaryItem, isGlossaryItem, isGlossaryPath } from "../utils/glossaryUtils";
|
|
import ErrorBoundary from "./ErrorBoundary";
|
|
import GlossaryDocCardList from "./GlossaryDocCardList";
|
|
import styles from "./styles.module.css";
|
|
|
|
// Docusaurus core imports
|
|
import type { PropSidebarItem } from "@docusaurus/plugin-content-docs";
|
|
import {
|
|
filterDocCardListItems,
|
|
useCurrentSidebarSiblings,
|
|
} from "@docusaurus/plugin-content-docs/client";
|
|
import { useLocation } from "@docusaurus/router";
|
|
import DocCard from "@theme/DocCard";
|
|
import type { Props } from "@theme/DocCardList";
|
|
import clsx from "clsx";
|
|
import React, { ReactNode, useMemo } from "react";
|
|
|
|
// Constant empty array to avoid creating new array on each render
|
|
const EMPTY_SIDEBAR_ITEMS: PropSidebarItem[] = [];
|
|
|
|
// Type aliases for clarity
|
|
type SidebarDocLike = Extract<PropSidebarItem, { type: "link" }>;
|
|
|
|
/**
|
|
* Type-safe property existence checker with proper typing
|
|
*/
|
|
function hasOwnProperty<T extends object, K extends PropertyKey>(
|
|
value: T,
|
|
key: K,
|
|
): value is T & Record<K, unknown> {
|
|
return Object.prototype.hasOwnProperty.call(value, key);
|
|
}
|
|
|
|
/**
|
|
* Generates stable React keys from sidebar items, with fallback to index
|
|
*/
|
|
function getStableKey(item: GlossaryItem | PropSidebarItem, idx: number): string | number {
|
|
if (typeof item === "object" && item !== null) {
|
|
const match = ["docId", "id", "href", "label"].find(
|
|
(name) => hasOwnProperty(item, name) && typeof item[name] === "string",
|
|
);
|
|
return match ? ((item as Record<string, unknown>)[match] as string) : idx;
|
|
}
|
|
return idx;
|
|
}
|
|
|
|
/**
|
|
* Standard documentation card item for non-glossary content
|
|
*/
|
|
function DocCardListItem({ item }: { item: React.ComponentProps<typeof DocCard>["item"] }) {
|
|
return (
|
|
<article className={clsx(styles.docCardListItem, "col col--6")}>
|
|
<DocCard item={item} />
|
|
</article>
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Enhanced DocCardList component that delegates to specialized components based on content type.
|
|
* Provides both standard documentation card rendering and specialized glossary functionality.
|
|
*/
|
|
export default function DocCardList(props: Props): ReactNode {
|
|
const { items, className } = props;
|
|
|
|
const pathname = useLocation()?.pathname ?? "";
|
|
const isGlossary = isGlossaryPath(pathname);
|
|
|
|
const sidebarSiblings = useCurrentSidebarSiblings();
|
|
const siblings = sidebarSiblings ?? EMPTY_SIDEBAR_ITEMS;
|
|
|
|
// Extract glossary terms from sidebar structure (always computed, but only used for glossary pages)
|
|
const glossaryPool = useMemo<SidebarDocLike[]>(() => {
|
|
const terms: SidebarDocLike[] = [];
|
|
|
|
// Recursively process sidebar items to find glossary terms
|
|
const processItem = (item: PropSidebarItem) => {
|
|
if (isGlossaryItem(item) && item.type === "link") {
|
|
terms.push(item as SidebarDocLike);
|
|
} else if (item.type === "category" && item.items) {
|
|
item.items.forEach(processItem);
|
|
}
|
|
};
|
|
|
|
siblings.forEach(processItem);
|
|
return terms;
|
|
}, [siblings]);
|
|
|
|
// Standard documentation card items (always computed, but only used for non-glossary pages)
|
|
const baseItems = useMemo(() => filterDocCardListItems(items ?? siblings), [items, siblings]);
|
|
|
|
// For glossary pages, delegate to specialized GlossaryDocCardList component
|
|
if (isGlossary) {
|
|
return (
|
|
<ErrorBoundary>
|
|
<GlossaryDocCardList glossaryPool={glossaryPool} className={className} />
|
|
</ErrorBoundary>
|
|
);
|
|
}
|
|
|
|
// Standard documentation card rendering for non-glossary pages
|
|
return (
|
|
<section className={clsx("row", className)}>
|
|
{baseItems.map((item, idx) => (
|
|
<DocCardListItem key={getStableKey(item, idx)} item={item} />
|
|
))}
|
|
</section>
|
|
);
|
|
}
|
|
|
|
export { DocCardList };
|