Skip to main content
Glama
index.tsx8.32 kB
import type { FC, HTMLAttributes, JSX, MouseEvent } from 'react'; import { cn } from '../../utils/cn'; const styledHeading = `relative scroll-mb-8 scroll-mt-[30vh] scroll-p-8`; const styledAfter = `after:content-['#'] after:scale-75 after:px-6 after:text-neutral after:absolute after:top-0 after:h-full after:-left-12 after:absolute after:to-neutral after:md:opacity-0 after:transition-opacity hover:after:opacity-80 after:duration-200 after:delay-100`; /** * Styled H1 Component * * Primary heading component for page titles and main content headers. * Does not include clickable anchor functionality. */ const StyledH1: FC<HTMLAttributes<HTMLHeadingElement>> = ({ className, ...props }) => <h1 className={cn('font-bold text-2xl', className)} {...props} />; /** * Styled H2 Component * * Secondary heading component with anchor link functionality when wrapped. * Used for major section headers in content. */ const StyledH2: FC<HTMLAttributes<HTMLHeadingElement>> = ({ className, ...props }) => ( <h2 className={cn('mb-2 font-bold text-2xl', styledHeading, className)} {...props} /> ); /** * Styled H3 Component * * Tertiary heading component with anchor link functionality when wrapped. * Used for subsection headers in content. */ const StyledH3: FC<HTMLAttributes<HTMLHeadingElement>> = ({ className, ...props }) => ( <h3 className={cn('mb-2 font-bold text-xl', styledHeading, className)} {...props} /> ); /** * Styled H4 Component * * Quaternary heading component with anchor link functionality when wrapped. * Used for minor section headers in content. */ const StyledH4: FC<HTMLAttributes<HTMLHeadingElement>> = ({ className, ...props }) => ( <h4 className={cn('font-bold text-lg', styledHeading, className)} {...props} /> ); /** * Styled H5 Component * * Fifth-level heading component with anchor link functionality when wrapped. * Used for detailed subsection headers in content. */ const StyledH5: FC<HTMLAttributes<HTMLHeadingElement>> = ({ className, ...props }) => ( <h5 className={cn('font-bold text-base', styledHeading, className)} {...props} /> ); const StyledH6: FC<HTMLAttributes<HTMLHeadingElement>> = ({ className, ...props }) => ( <h6 className={cn('ml-3 font-bold text-base', styledHeading, className)} {...props} /> ); /** * Props for heading components */ export type HeadingProps = HTMLAttributes<HTMLHeadingElement> & { /** * Whether the heading should be clickable with anchor link functionality. * Enables copy-to-clipboard URL behavior and smooth scrolling. * @default false (for H1), true (for H2-H5) */ isClickable?: boolean; }; /** * Internal props for the HeadingWrapper component */ interface HeadingGlobalProps extends HeadingProps { /** The styled heading component to render */ H: FC<HTMLAttributes<HTMLHeadingElement>>; } type HeadingType = (props: HeadingGlobalProps) => JSX.Element; /** * Utility function to generate URL-friendly ID from heading text * @param children - The heading text content * @returns URL-friendly string for use as element ID */ const getId = (children: string) => String(children) // replace accents .normalize('NFD') .replace(/[\u0300-\u036f]/g, '') // replace spaces .replace(/\s+/g, '-') .toLowerCase(); /** * Utility function to smoothly scroll to an element by ID * @param id - The element ID to scroll to */ const scrollToHash = (id: string) => { const element = document.getElementById(id); const offset = 150; const y = (element?.getBoundingClientRect()?.top ?? 0) + window.scrollY - offset; window.scrollTo({ top: y, behavior: 'smooth' }); }; /** * Utility function to detect if the pseudo-element (#) after the heading was clicked * @param parentElem - The heading element * @param e - Mouse event * @returns Whether the after pseudo-element was clicked */ const afterClick = (parentElem: Element, e: MouseEvent<HTMLHeadingElement>) => { const parentLeft = parentElem.getBoundingClientRect().left; const parentTop = parentElem.getBoundingClientRect().top; const after = window.getComputedStyle(parentElem, ':after'); const afterStart = parentLeft + parseInt(after.getPropertyValue('left'), 10); const afterEnd = afterStart + parseInt(after.width, 10); const afterYStart = parentTop + parseInt(after.getPropertyValue('top'), 10); const afterYEnd = afterYStart + parseInt(after.height, 10); const mouseX = e.clientX; const mouseY = e.clientY; const isAfterClicked: boolean = mouseX >= afterStart && mouseX <= afterEnd && mouseY >= afterYStart && mouseY <= afterYEnd; return isAfterClicked; }; /** * HeadingWrapper Component * * Internal wrapper component that adds anchor link functionality to headings. * Handles ID generation, click-to-copy URL behavior, and smooth scrolling. * * @component * @accessibility * - Generates URL-friendly IDs for deep linking * - Provides accessible labels for anchor link functionality * - Maintains proper heading hierarchy and semantics * - Supports keyboard navigation and screen readers */ const HeadingWrapper: HeadingType = ({ H, children, className, isClickable, ...props }) => { const id = typeof children === 'string' ? getId(children) : undefined; const onClick = (e: MouseEvent<HTMLHeadingElement>) => { const { id } = e.currentTarget; const isAfterClicker = afterClick(e.currentTarget, e); if (isAfterClicker && typeof id === 'string') { const urlWithoutHash = window.location.href.split('#')[0]; const url = `${urlWithoutHash}#${id}`; // copy the url to the clipboard navigator.clipboard.writeText(url); scrollToHash(id); } }; return ( <H id={id} onClick={isClickable ? onClick : undefined} aria-label={ isClickable ? `Click to scroll to section ${id} and copy the link to the clipboard` : undefined } className={cn(isClickable && styledAfter, className)} {...props} > {children} </H> ); }; /** * H1 Component * * Primary page heading component. Does not include clickable anchor functionality * as it's typically used for main page titles rather than content sections. * * @example * ```tsx * <H1>Welcome to Our Website</H1> * <H1 className="text-blue-600">Custom Styled Title</H1> * ``` */ export const H1: FC<HeadingProps> = ({ isClickable: _, ...props }) => ( <StyledH1 {...props} /> ); /** * H2 Component * * Secondary heading component with optional anchor link functionality. * Perfect for major section headers with deep-linking capabilities. * * @example * ```tsx * <H2>Getting Started</H2> * <H2 isClickable>API Reference</H2> * ``` */ export const H2: FC<HeadingProps> = ({ isClickable = false, ...props }) => ( <HeadingWrapper H={StyledH2} isClickable={isClickable} {...props} /> ); /** * H3 Component * * Tertiary heading component with optional anchor link functionality. * Used for subsection headers within major sections. * * @example * ```tsx * <H3>Configuration Options</H3> * <H3 isClickable>Advanced Settings</H3> * ``` */ export const H3: FC<HeadingProps> = ({ isClickable = false, ...props }) => ( <HeadingWrapper H={StyledH3} isClickable={isClickable} {...props} /> ); /** * H4 Component * * Fourth-level heading component with optional anchor link functionality. * Used for detailed section organization. * * @example * ```tsx * <H4>Implementation Details</H4> * <H4 isClickable>Code Examples</H4> * ``` */ export const H4: FC<HeadingProps> = ({ isClickable = false, ...props }) => ( <HeadingWrapper H={StyledH4} isClickable={isClickable} {...props} /> ); /** * H5 Component * * Fifth-level heading component with optional anchor link functionality. * Used for fine-grained content organization. * * @example * ```tsx * <H5>Technical Notes</H5> * <H5 isClickable>Best Practices</H5> * ``` */ export const H5: FC<HeadingProps> = ({ isClickable = false, ...props }) => ( <HeadingWrapper H={StyledH5} isClickable={isClickable} {...props} /> ); export const H6: FC<HeadingProps> = ({ isClickable = false, ...props }) => ( <HeadingWrapper H={StyledH6} isClickable={isClickable} {...props} /> );

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/aymericzip/intlayer'

If you have feedback or need assistance with the MCP directory API, please join our Discord server