import * as React from 'react' import { useThemeConfig, useThemeHooks } from '@redocly/theme/core/hooks' import { LanguagePicker } from '@redocly/theme/components/LanguagePicker/LanguagePicker' import { slugify } from '../../helpers' import { Link } from '@redocly/theme/components/Link/Link' import { ColorModeSwitcher } from '@redocly/theme/components/ColorModeSwitcher/ColorModeSwitcher' import { Search } from '@redocly/theme/components/Search/Search' import arrowUpRight from '../../../static/img/icons/arrow-up-right-custom.svg' import moment from 'moment-timezone' // @ts-ignore const alertBanner = { show: false, message: 'APEX 2025', button: 'REGISTER', link: 'https://www.xrpledgerapex.com/?utm_source=xrplwebsite&utm_medium=direct&utm_campaign=xrpl-event-ho-xrplapex-glb-2025-q1_xrplwebsite_ari_arp_bf_rsvp&utm_content=cta_btn_english_pencilbanner', } export function AlertBanner({ message, button, link, show }) { const { useTranslate } = useThemeHooks() const { translate } = useTranslate() const bannerRef = React.useRef(null) const [displayDate, setDisplayDate] = React.useState('JUNE 10-12') React.useEffect(() => { const calculateCountdown = () => { // Calculate days until June 11, 2025 8AM Singapore time // This will automatically adjust for the user's timezone const target = moment.tz('2025-06-11 08:00:00', 'Asia/Singapore') const now = moment() const daysUntil = target.diff(now, 'days') // Show countdown if event is in the future, otherwise show the provided date let newDisplayDate = 'JUNE 10-12' if (daysUntil > 0) { newDisplayDate = daysUntil === 1 ? 'IN 1 DAY' : `IN ${daysUntil} DAYS` } else if (daysUntil === 0) { // Check if it's today const hoursUntil = target.diff(now, 'hours') newDisplayDate = hoursUntil > 0 ? 'TODAY' : 'JUNE 10-12' } setDisplayDate(newDisplayDate) } // Calculate immediately calculateCountdown() // Update every hour const interval = setInterval(calculateCountdown, 60 * 60 * 1000) return () => clearInterval(interval) }, []) React.useEffect(() => { const banner = bannerRef.current if (!banner) return const handleMouseEnter = () => { banner.classList.add('has-hover') } // Attach the event listener banner.addEventListener('mouseenter', handleMouseEnter) // Clean up the event listener on unmount return () => { banner.removeEventListener('mouseenter', handleMouseEnter) } }, []) if (show) { return (
{translate(message)}
{displayDate}
{translate(button)}
Get Tickets Icon
) } return null } export function Navbar(props) { // const [isOpen, setIsOpen] = useMobileMenu(false); const themeConfig = useThemeConfig() const { useL10n } = useThemeHooks() const { changeLanguage } = useL10n() const menu = themeConfig.navbar?.items const logo = themeConfig.logo const { href, altText, items } = props const pathPrefix = '' const navItems = menu.map((item, index) => { if (item.type === 'group') { return } else { return ( {item.label} ) } }) React.useEffect(() => { // Turns out jQuery is necessary for firing events on Bootstrap v4 // dropdowns. These events set classes so that the search bar and other // submenus collapse on mobile when you expand one submenu. const dds = $('#topnav-pages .dropdown') const top_main_nav = document.querySelector('#top-main-nav') dds.on('show.bs.dropdown', (evt) => { top_main_nav.classList.add('submenu-expanded') }) dds.on('hidden.bs.dropdown', (evt) => { top_main_nav.classList.remove('submenu-expanded') }) // Close navbar on .dropdown-item click const toggleNavbar = () => { const navbarToggler = document.querySelector('.navbar-toggler') const isNavbarCollapsed = navbarToggler.getAttribute('aria-expanded') === 'true' if (isNavbarCollapsed) { navbarToggler?.click() // Simulate click to toggle navbar } } const dropdownItems = document.querySelectorAll('.dropdown-item') dropdownItems.forEach((item) => { item.addEventListener('click', toggleNavbar) }) // Cleanup function to remove event listeners return () => { dropdownItems.forEach((item) => { item.removeEventListener('click', toggleNavbar) }) } }, []) return ( <> {navItems}
) } export function TopNavCollapsible({ children }) { return (
{children}
) } export function NavDropdown(props) { const { label, items, pathPrefix, labelTranslationKey } = props const { useTranslate } = useThemeHooks() const { translate } = useTranslate() const dropdownGroups = items.map((item, index) => { if (item.items) { const groupLinks = item.items.map((item2, index2) => { const cls2 = item2.external ? 'dropdown-item external-link' : 'dropdown-item' let item2_href = item2.link if (item2_href && !item2_href.match(/^https?:/)) { item2_href = pathPrefix + item2_href } //conditional specific for brand kit if (item2.link === '/XRPL_Brand_Kit.zip') { return ( {translate(item2.labelTranslationKey, item2.label)} ) } return ( {translate(item2.labelTranslationKey, item2.label)} ) }) const clnm = 'navcol col-for-' + slugify(item.label) return (
{translate(item.labelTranslationKey, item.label)}
{groupLinks}
) } else if (item.icon) { const hero_id = 'dropdown-hero-for-' + slugify(label) const img_alt = item.label + ' icon' let hero_href = item.link if (hero_href && !hero_href.match(/^https?:/)) { hero_href = pathPrefix + hero_href } const splitlabel = item.label.split(' || ') let splittranslationkey = ['', ''] if (item.labelTranslationKey) { splittranslationkey = item.labelTranslationKey.split(' || ') } const newlabel = translate(splittranslationkey[0], splitlabel[0]) const description = translate(splittranslationkey[1], splitlabel[1]) // splitlabel[1] might be undefined, that's ok return ( {img_alt}

{newlabel}

{description}

) } else { const cls = item.external ? 'dropdown-item ungrouped external-link' : 'dropdown-item ungrouped' let item_href = item.link if (item_href && !item_href.match(/^https?:/)) { item_href = pathPrefix + item_href } return ( {translate(item.labelTranslationKey, item.label)} ) } }) const toggler_id = 'topnav_' + slugify(label) const dd_id = 'topnav_dd_' + slugify(label) return (
  • {dropdownGroups}
  • ) } export function NavWrapper(props) { return ( ) } export function NavControls(props) { return ( ) } export function MobileMenuIcon() { return (
    ) } export function GetStartedButton() { const { useTranslate } = useThemeHooks() const { translate } = useTranslate() return ( {translate('Get Started')} ) } export function NavItems(props) { return ( ) } export function NavItem(props) { return
  • {props.children}
  • } export function LogoBlock(props) { const { to, img, altText } = props return ( {'XRP ) } export class ThemeToggle extends React.Component { auto_update_theme() { const upc = window.localStorage.getItem('user-prefers-color') let theme = 'dark' // Default to dark theme if (!upc) { // User hasn't saved a preference specifically for this site; check // the browser-level preferences. if (window.matchMedia && window.matchMedia('(prefers-color-scheme: light)').matches) { theme = 'light' } } else { // Follow user's saved setting. theme = upc == 'light' ? 'light' : 'dark' } const disable_theme = theme == 'dark' ? 'light' : 'dark' document.documentElement.classList.add(theme) document.documentElement.classList.remove(disable_theme) } user_choose_theme() { const new_theme = document.documentElement.classList.contains('dark') ? 'light' : 'dark' window.localStorage.setItem('user-prefers-color', new_theme) document.body.style.transition = 'background-color .2s ease' const disable_theme = new_theme == 'dark' ? 'light' : 'dark' document.documentElement.classList.add(new_theme) document.documentElement.classList.remove(disable_theme) } render() { return (
    ) } componentDidMount() { this.auto_update_theme() } }