import { IconClose, Link, mergeRefs, SvgWrapper } from '@rspress/core/theme'; import clsx from 'clsx'; import { forwardRef, type ReactNode, useEffect, useState } from 'react'; import './index.scss'; export type BannerProps = { /** * @default true */ display?: boolean; className?: string; } & ( | { /** * @default 'localStorage' */ storage?: 'localStorage' | 'sessionStorage' | false; /** * @default 'rp-banner-closed' */ storageKey?: string; href: string; message: string | ReactNode; } | { customChildren: ReactNode; } ); /** * @example * // theme/index.tsx * import { Layout as BasicLayout, Banner } from '@rspress/core/theme-original'; * import { useLang } from '@rspress/core/runtime'; * const Layout = () => { const lang = useLang(); return ( } /> ); }; export { Layout } * */ export const Banner = forwardRef( (props, forwardedRef) => { const { href, message, display = true, className, storageKey = 'rp-banner-closed', storage = 'localStorage', customChildren, } = props as { href?: string; message?: string | ReactNode; display?: boolean; className?: string; storageKey?: string; storage?: 'localStorage' | 'sessionStorage' | false; customChildren?: ReactNode; }; const [height, setHeight] = useState(36); const ref = mergeRefs(forwardedRef, element => { if (element?.offsetHeight) { setHeight(element?.offsetHeight); } }); const [disable, setDisable] = useState(false); // TODO: support SSR useEffect(() => { if (typeof window === 'undefined' || !storage || !storageKey) { return; } setDisable(Boolean(window[storage].getItem(storageKey))); }, []); if (!display || disable) { return null; } return ( <>
{customChildren ?? ( <> {message} { setDisable(true); if (storage) { window[storage].setItem(storageKey, 'true'); } }} className="rp-banner__close" /> )}
); }, );