{"version":3,"file":"js/application-bundle-3744520cd19c58a7aa4b.js","mappings":"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","sources":["webpack://app/./app/javascript/bundles/Main/components/Icon.tsx","webpack://app/./app/javascript/bundles/Main/components/ListItem.tsx","webpack://app/./app/javascript/bundles/Main/components/UserSearchBar.tsx","webpack://app/./app/javascript/bundles/Main/utils/hoverPreviewUtils.ts","webpack://app/./app/javascript/bundles/Main/components/HoverPreview.tsx","webpack://app/./app/javascript/bundles/Main/components/PostHoverPreview.tsx","webpack://app/./app/javascript/bundles/Main/components/PostHoverPreviewWrapper.tsx","webpack://app/./app/javascript/bundles/Main/components/UserHoverPreview.tsx","webpack://app/./app/javascript/bundles/Main/components/UserHoverPreviewWrapper.tsx","webpack://app/./app/javascript/bundles/UI/collapsibleSections.ts","webpack://app/./app/javascript/bundles/UI/utils/ipValidation.ts","webpack://app/./app/javascript/bundles/UI/components/IpAddressInput.tsx","webpack://app/./app/javascript/packs/application-bundle.js","webpack://app/./app/javascript/bundles/Main/components/UserMenu.tsx"],"sourcesContent":["import * as React from 'react';\n\ninterface PropTypes {\n type: 'magnifying-glass' | 'exclamation-circle' | 'spinner';\n className?: string;\n}\nexport default function Icon(props: PropTypes) {\n const { type } = props;\n const className = `w-6 h-6 pointer-events-none absolute\n transform top-1/2 -translate-y-1/2 ${props.className}`;\n\n switch (type) {\n case 'magnifying-glass':\n return (\n \n \n \n );\n\n case 'spinner':\n return (\n \n \n \n \n \n );\n\n case 'exclamation-circle':\n return (\n \n \n \n );\n }\n}\n","import * as React from 'react';\nimport Icon from './Icon';\n\nconst COMMON_LIST_ELEM_CLASSES = `\n w-full p-2\n text-xl font-light\n border-inherit\n group-focus-within:border-slate-300\n`;\n\ninterface PropTypes {\n value: string;\n subtext?: string;\n thumb?: string;\n isLast: boolean;\n selected: boolean;\n href?: string;\n style: 'item' | 'info' | 'error';\n domainIcon?: string;\n}\n\nexport default function ListItem({\n value,\n thumb,\n isLast,\n selected,\n style,\n href,\n subtext,\n domainIcon,\n}: PropTypes) {\n const iconClassName = ['ml-2'];\n const textClassName = [\n COMMON_LIST_ELEM_CLASSES,\n 'relative flex items-center justify-between',\n 'border-t-0',\n isLast && 'rounded-b-lg',\n style === 'item' && selected && 'bg-slate-700 text-slate-100',\n style === 'info' && 'text-slate-500 italic',\n style === 'error' && 'text-red-500',\n 'hover:bg-slate-600 hover:text-slate-200',\n ].filter(Boolean);\n\n return (\n {\n if (href) {\n window.location.href = href;\n }\n }}\n href={href}\n >\n {style === 'error' && (\n \n )}\n
\n
\n {thumb && (\n \n )}\n
\n
{value}
\n {subtext && (\n
\n {subtext}\n
\n )}\n {domainIcon && (\n \"domain\n )}\n
\n \n );\n}\n","import { debounce, isEmpty } from 'lodash';\nimport * as React from 'react';\nimport { useCallback, useRef, useState } from 'react';\nimport Icon from './Icon';\nimport ListItem from './ListItem';\nimport Trie, { TrieNode } from '../lib/Trie';\n\n// 1. Group related constants\nconst CONFIG = {\n HOST: '',\n LOG: false,\n} as const;\n\nconst STYLES = {\n LIST_ELEM_CLASSNAME: [\n 'w-full p-2 pl-8 text-xl font-light border-slate-300 border-2',\n 'group-focus-within:border-slate-400',\n ],\n SVG_BASE_CLASSNAME: `stroke-slate-500 fill-slate-500`,\n SVG_FOCUSABLE_CLASSNAME: `stroke-slate-500 fill-slate-500 group-focus-within:stroke-slate-800 group-focus-within:fill-slate-800`,\n INPUT_CLASSNAME: `text-slate-500 group-focus-within:text-slate-800 placeholder-slate-500 group-focus-within:placeholder-slate-800 placeholder:font-extralight`,\n} as const;\n\n// 2. Simplify logging\nconst log = {\n info: (...args: any[]) => CONFIG.LOG && console.log(...args),\n error: (...args: any[]) => CONFIG.LOG && console.error(...args),\n};\n\ninterface PropTypes {\n isServerRendered?: boolean;\n}\n\ninterface User {\n id: number;\n name: string;\n thumb?: string;\n show_path: string;\n num_posts?: number;\n distance: number;\n matched_name: string;\n domain_icon: string;\n}\n\ninterface ServerResponse {\n users: User[];\n}\n\ntype TrieValue = [number, string];\ntype TrieType = Trie;\ntype TrieNodeType = TrieNode;\n\nexport default function UserSearchBar({ isServerRendered }: PropTypes) {\n isServerRendered = !!isServerRendered;\n const [pendingRequest, setPendingRequest] = useState(\n null,\n );\n const [state, setState] = useState({\n userName: '',\n userList: [] as ServerResponse['users'],\n selectedIdx: null as number | null,\n errorMessage: null as string | null,\n typingSettled: true,\n isFocused: isServerRendered ? false : true,\n });\n\n const inputRef = useRef(null);\n\n const clearResults = useCallback(() => {\n setState((s) => ({\n ...s,\n userList: [],\n errorMessage: null,\n selectedIdx: null,\n }));\n }, []);\n\n const cancelPendingRequest = useCallback(async () => {\n if (pendingRequest) {\n setPendingRequest(null);\n pendingRequest.abort();\n }\n }, [pendingRequest, setPendingRequest]);\n\n const sendSearchRequest = useCallback(\n (userName) => {\n cancelPendingRequest();\n\n const controller = new AbortController();\n setPendingRequest(controller);\n\n async function sendRequest() {\n try {\n let req = await fetch(\n `${CONFIG.HOST}/users/search_by_name.json?name=${userName}`,\n {\n signal: controller.signal,\n },\n );\n\n setPendingRequest(null);\n setState((s) => ({\n ...s,\n errorMessage: null,\n }));\n\n if (req.status != 200) {\n const error_json = await req.json();\n setState((s) => ({\n ...s,\n errorMessage: `error loading users: ${error_json.error || JSON.stringify(error_json)}`,\n }));\n } else {\n let gotUserList = await req.json();\n setState((s) => ({\n ...s,\n userList: gotUserList.users,\n }));\n }\n } catch (err) {\n if (!err.message.includes('aborted')) {\n log.error('error loading user trie: ', err);\n setState((s) => ({\n ...s,\n errorMessage: `error loading users: ` + err.message,\n }));\n }\n }\n }\n sendRequest();\n\n return () => controller.abort();\n },\n [cancelPendingRequest, setPendingRequest],\n );\n\n const searchForUser = useCallback(\n (userName: string) => {\n setState((s) => ({ ...s, userName }));\n if (isEmpty(userName)) {\n clearResults();\n } else {\n sendSearchRequest(userName);\n }\n },\n [clearResults, sendSearchRequest],\n );\n\n const searchForUserDebounced = useCallback(\n debounce(async (userName) => {\n log.info('sending search for ', userName);\n setState((s) => ({ ...s, typingSettled: true }));\n searchForUser(userName);\n }, 250),\n [searchForUser],\n );\n\n function invokeIdx(idx) {\n const user = state.userList[idx];\n if (user) {\n log.info('selecting user: ', user);\n setState((s) => ({ ...s, userName: user.name }));\n inputRef.current.value = user.name;\n window.location.href = user.show_path;\n }\n }\n\n function invokeSelected() {\n if (state.selectedIdx != null) {\n invokeIdx(state.selectedIdx);\n }\n }\n\n const visibility = {\n error: state.isFocused && !isEmpty(state.errorMessage),\n info:\n state.isFocused &&\n !isEmpty(state.userName) &&\n !pendingRequest &&\n state.typingSettled &&\n state.userList.length === 0,\n items: !isEmpty(state.userName) && state.userList.length > 0,\n };\n const anyShown = Object.values(visibility).some(Boolean);\n\n function UserSearchBarItems() {\n return (\n \n {visibility.error ? (\n \n ) : null}\n {visibility.info ? (\n \n ) : null}\n {visibility.items\n ? state.userList.map(\n ({ name, thumb, show_path, num_posts, domain_icon }, idx) => (\n \n ),\n )\n : null}\n \n );\n }\n\n const keyHandlers = {\n Tab: (shiftKey: boolean) =>\n shiftKey ? selectPrevListElem() : selectNextListElem(),\n ArrowDown: () => selectNextListElem(),\n ArrowUp: () => selectPrevListElem(),\n Enter: () => invokeSelected(),\n };\n\n function onSearchInputKeyDown(event: React.KeyboardEvent) {\n const handler = keyHandlers[event.code];\n if (handler) {\n event.preventDefault();\n handler(event.shiftKey);\n }\n }\n\n function selectNextListElem() {\n setNewIdxTruncated(state.selectedIdx == null ? 0 : state.selectedIdx + 1);\n }\n\n function selectPrevListElem() {\n setNewIdxTruncated(state.selectedIdx == null ? -1 : state.selectedIdx - 1);\n }\n\n function setNewIdxTruncated(newIdx) {\n if (state.userList.length == 0) {\n newIdx = null;\n } else {\n if (newIdx >= state.userList.length) {\n newIdx = 0;\n } else if (newIdx < 0) {\n newIdx = state.userList.length - 1;\n }\n }\n setState((s) => ({ ...s, selectedIdx: newIdx }));\n }\n\n return (\n \n \n \n \n );\n}\n","import {\n RefObject,\n CSSProperties,\n useState,\n useRef,\n useEffect,\n useMemo,\n} from 'react';\n\n/**\n * Utility functions for hover preview styling\n */\n\nexport type IconSize = 'large' | 'small';\nexport function iconClassNamesForSize(size: IconSize) {\n switch (size) {\n case 'large':\n return 'h-8 w-8 flex-shrink-0 rounded-md';\n case 'small':\n return 'h-5 w-5 flex-shrink-0 rounded-sm';\n }\n}\n\n// Base preview container styling\nexport const getPreviewContainerClassName = (\n maxWidth: string,\n maxHeight: string,\n) => {\n // calculate if the page is mobile\n const isMobile = window.innerWidth < 640;\n return [\n isMobile ? 'hidden' : '',\n `max-w-[${maxWidth}] max-h-[${maxHeight}] rounded-lg`,\n 'border border-slate-400 bg-slate-100',\n 'divide-y divide-slate-300',\n 'shadow-lg shadow-slate-500/30',\n ].join(' ');\n};\n\n// Header/Footer styling\nexport const getHeaderFooterClassName = () => {\n return [\n 'flex items-center overflow-hidden',\n 'border-slate-400 bg-gradient-to-r from-slate-200 to-slate-300 p-2',\n ].join(' ');\n};\n\n// Content area styling\nexport const getContentClassName = () => {\n return 'bg-slate-100 p-3';\n};\n\n// Text styling functions\nexport const getHeaderTextClassName = () => {\n return 'mr-2 min-w-0 truncate text-sm font-semibold text-slate-700';\n};\n\nexport const getLabelTextClassName = () => {\n return 'text-2xs text-slate-700';\n};\n\nexport const getValueTextClassName = () => {\n return 'block text-sm font-semibold text-slate-700';\n};\n\nexport const getSecondaryTextClassName = () => {\n return 'text-sm italic text-slate-600';\n};\n\n// Border and shadow styling\nexport const getBorderClassName = () => {\n return 'border border-slate-300';\n};\n\n// Avatar container styling\nexport const getAvatarContainerClassName = () => {\n return 'overflow-hidden rounded-md';\n};\n\n// Base avatar image styling\nexport const getAvatarImageClassName = (size: string = 'medium') => {\n const sizeClasses = {\n small: 'h-6 w-6',\n medium: 'h-[80px] w-[80px]',\n large: 'h-20 w-20',\n };\n\n return `${sizeClasses[size as keyof typeof sizeClasses]} rounded-md ${getBorderClassName()} object-cover shadow-sm`;\n};\n\n// Icon styling\nexport const getIconClassName = () => {\n return 'h-8 w-8 rounded-md p-1';\n};\n\n/**\n * Calculate the position for a hover preview popup\n * @param containerRef The reference to the element containing the hover trigger\n * @param previewRef The reference to the popup element\n * @returns CSS properties for positioning the popup or undefined if refs are not available\n */\nexport const calculatePreviewPosition = (\n containerRef: RefObject,\n previewRef: RefObject,\n): CSSProperties | undefined => {\n if (!containerRef.current || !previewRef.current) return undefined;\n\n // Get dimensions\n const linkRect = containerRef.current.getBoundingClientRect();\n const previewRect = previewRef.current.getBoundingClientRect();\n const viewport = {\n width: window.innerWidth,\n height: window.innerHeight,\n };\n\n // Determine horizontal position\n const spaceRight = viewport.width - linkRect.right;\n const spaceLeft = linkRect.left;\n const showOnRight = spaceRight > spaceLeft;\n\n // Calculate vertical center alignment\n const linkCenter = linkRect.top + linkRect.height / 2;\n const padding =\n parseInt(getComputedStyle(document.documentElement).fontSize) * 2; // 2em\n\n // Calculate preferred vertical position (centered with link)\n let top = linkCenter - previewRect.height / 2;\n\n // Adjust if too close to viewport edges\n if (top < padding) top = padding;\n if (top + previewRect.height > viewport.height - padding) {\n top = viewport.height - previewRect.height - padding;\n }\n\n // Return position\n return {\n position: 'fixed',\n zIndex: 9999,\n top: `${top}px`,\n overflow: 'auto',\n transition: 'opacity 0.2s ease-in-out',\n ...(showOnRight\n ? { left: `${linkRect.right + 10}px` }\n : { right: `${viewport.width - linkRect.left + 10}px` }),\n };\n};\n\n/**\n * Get initial offscreen position style for measurement\n */\nexport const getOffscreenMeasurementStyle = (): CSSProperties => {\n return {\n position: 'fixed',\n left: '-9999px',\n top: '0',\n opacity: '0',\n transition: 'opacity 0.2s ease-in-out',\n };\n};\n\n/**\n * Custom hook for handling hover preview functionality\n */\nexport const useHoverPreview = () => {\n const [showPreview, setShowPreview] = useState(false);\n const [previewStyle, setPreviewStyle] = useState({});\n const containerRef = useRef(null);\n const previewRef = useRef(null);\n\n // Create portal container once\n const portalContainer = useMemo(() => document.createElement('div'), []);\n\n // Setup portal container\n useEffect(() => {\n document.body.appendChild(portalContainer);\n return () => {\n document.body.removeChild(portalContainer);\n };\n }, [portalContainer]);\n\n // Position and display the preview\n const updatePosition = () => {\n const newPosition = calculatePreviewPosition(containerRef, previewRef);\n if (newPosition) {\n setPreviewStyle(newPosition);\n }\n };\n\n // Two-step approach: first measure offscreen, then show\n const handleMouseEnter = () => {\n // Step 1: Render offscreen for measurement\n setPreviewStyle(getOffscreenMeasurementStyle());\n setShowPreview(true);\n\n // Step 2: Position properly after a very short delay\n setTimeout(() => {\n updatePosition();\n }, 20);\n };\n\n const handleMouseLeave = () => {\n setShowPreview(false);\n };\n\n // Handle window resize\n useEffect(() => {\n if (!showPreview) return;\n\n window.addEventListener('resize', updatePosition);\n return () => {\n window.removeEventListener('resize', updatePosition);\n };\n }, [showPreview]);\n\n return {\n containerRef,\n previewRef,\n portalContainer,\n showPreview,\n previewStyle,\n handleMouseEnter,\n handleMouseLeave,\n };\n};\n\nexport function anchorClassNamesForVisualStyle(\n visualStyle: string,\n hasIcon: boolean = false,\n) {\n let classNames = ['truncate', 'gap-1'];\n if (hasIcon) {\n classNames.push('flex items-center');\n }\n return classNames.join(' ');\n}\n","import * as React from 'react';\nimport { ReactNode } from 'react';\nimport { createPortal } from 'react-dom';\nimport {\n useHoverPreview,\n getPreviewContainerClassName,\n} from '../utils/hoverPreviewUtils';\n\nexport interface HoverPreviewProps {\n children: ReactNode;\n previewContent: ReactNode;\n previewClassName?: string;\n maxWidth?: string;\n maxHeight?: string;\n}\n\nexport const HoverPreview: React.FC = ({\n children,\n previewContent,\n previewClassName = '',\n maxWidth = '300px',\n maxHeight = '500px',\n}) => {\n // Use shared hover preview hook\n const {\n containerRef,\n previewRef,\n portalContainer,\n showPreview,\n previewStyle,\n handleMouseEnter,\n handleMouseLeave,\n } = useHoverPreview();\n\n return (\n \n {children}\n\n {showPreview &&\n createPortal(\n \n {previewContent}\n ,\n portalContainer,\n )}\n \n );\n};\n\nexport default HoverPreview;\n","import * as React from 'react';\nimport { HoverPreview } from './HoverPreview';\nimport {\n getHeaderFooterClassName,\n getContentClassName,\n getHeaderTextClassName,\n getSecondaryTextClassName,\n getBorderClassName,\n getIconClassName,\n getAvatarImageClassName,\n} from '../utils/hoverPreviewUtils';\n\ninterface PostHoverPreviewProps {\n children: React.ReactNode;\n postTitle: string;\n postThumbnailPath?: string;\n postThumbnailAlt?: string;\n postDomainIcon?: string;\n creatorName?: string;\n creatorAvatarPath?: string;\n}\n\nexport const PostHoverPreview: React.FC = ({\n children,\n postTitle,\n postThumbnailPath,\n postThumbnailAlt,\n postDomainIcon,\n creatorName,\n creatorAvatarPath,\n}) => {\n // Force eager loading of images\n React.useEffect(() => {\n // Preload post thumbnail\n if (postThumbnailPath) {\n const thumbnailImg = new Image();\n thumbnailImg.src = postThumbnailPath;\n }\n\n // Preload creator avatar\n if (creatorAvatarPath) {\n const avatarImg = new Image();\n avatarImg.src = creatorAvatarPath;\n }\n }, [postThumbnailPath, creatorAvatarPath]);\n\n // Add extra classes for PostHoverPreview's header/footer\n const postHeaderFooterClassName = `${getHeaderFooterClassName()} justify-between p-3`;\n\n const previewContent = (\n <>\n {/* Header: Title */}\n
\n \n {postTitle}\n \n
\n\n {/* Image Content */}\n \n {postThumbnailPath ? (\n
\n \n
\n ) : (\n \n {postThumbnailAlt || 'No file available'}\n \n )}\n \n\n {/* Footer: Domain icon & Creator */}\n {creatorName && (\n
\n \n {creatorAvatarPath && (\n \n )}\n \n {creatorName}\n \n \n {(postDomainIcon && (\n \n )) || (\n \n )}\n
\n )}\n \n );\n\n return (\n \n );\n};\n\nexport default PostHoverPreview;\n","import * as React from 'react';\nimport PostHoverPreview from './PostHoverPreview';\nimport {\n anchorClassNamesForVisualStyle,\n iconClassNamesForSize,\n} from '../utils/hoverPreviewUtils';\n\ninterface PostHoverPreviewWrapperProps {\n visualStyle: 'sky-link' | 'description-section-link';\n linkText: string;\n postTitle: string;\n postPath: string;\n postThumbnailPath: string;\n postThumbnailAlt: string;\n postDomainIcon: string;\n creatorName?: string;\n creatorAvatarPath?: string;\n}\n\nexport const PostHoverPreviewWrapper: React.FC<\n PostHoverPreviewWrapperProps\n> = ({\n visualStyle,\n linkText,\n postTitle,\n postPath,\n postThumbnailPath,\n postThumbnailAlt,\n postDomainIcon,\n creatorName,\n creatorAvatarPath,\n}) => {\n return (\n \n \n {visualStyle === 'description-section-link' && (\n \n )}\n {linkText}\n \n \n );\n};\n\nexport default PostHoverPreviewWrapper;\n","import * as React from 'react';\nimport { HoverPreview } from './HoverPreview';\nimport {\n getHeaderFooterClassName,\n getContentClassName,\n getHeaderTextClassName,\n getLabelTextClassName,\n getValueTextClassName,\n getSecondaryTextClassName,\n getAvatarContainerClassName,\n getAvatarImageClassName,\n getIconClassName,\n} from '../utils/hoverPreviewUtils';\n\ninterface UserHoverPreviewProps {\n children: React.ReactNode;\n userName: string;\n userAvatarPath: string;\n userAvatarAlt: string;\n userDomainIcon?: string;\n userRegisteredAt?: string;\n userNumPosts?: number;\n userNumFollowedBy?: number;\n userNumFollowed?: number;\n}\n\nexport const UserHoverPreview: React.FC = ({\n children,\n userName,\n userAvatarPath,\n userAvatarAlt,\n userDomainIcon,\n userRegisteredAt,\n userNumPosts,\n userNumFollowedBy,\n userNumFollowed,\n}) => {\n // Force eager loading of the avatar image\n React.useEffect(() => {\n if (userAvatarPath) {\n const img = new Image();\n img.src = userAvatarPath;\n }\n }, [userAvatarPath]);\n\n const previewContent = (\n <>\n {/* Header: User Name and Domain Icon */}\n
\n \n {userName}\n \n {userDomainIcon && (\n \n )}\n
\n\n {/* Profile Content */}\n
\n
\n {/* Avatar */}\n
\n {userAvatarPath ? (\n
\n \n
\n ) : (\n \n No avatar\n \n )}\n
\n\n {/* User Stats */}\n
\n
\n
\n \n {userNumPosts ?? '-'}\n \n Posts\n
\n\n
\n \n {userNumFollowedBy ?? '-'}\n \n Followers\n
\n\n
\n \n {userNumFollowed ?? '-'}\n \n Following\n
\n\n
\n {userRegisteredAt && (\n <>\n \n Member since\n \n \n {userRegisteredAt}\n \n \n )}\n
\n
\n
\n
\n
\n \n );\n\n return (\n \n );\n};\n\nexport default UserHoverPreview;\n","import * as React from 'react';\nimport { UserHoverPreview } from './UserHoverPreview';\nimport {\n anchorClassNamesForVisualStyle,\n iconClassNamesForSize,\n} from '../utils/hoverPreviewUtils';\n\ntype VisualStyle = 'sky-link' | 'description-section-link';\ntype IconSize = 'small' | 'large';\n\ninterface UserHoverPreviewWrapperProps {\n visualStyle: VisualStyle;\n iconSize: IconSize;\n linkText: string;\n userId: string;\n userName: string;\n userPath: string;\n userAvatarPath: string;\n userAvatarAlt: string;\n userDomainIcon?: string;\n userSmallAvatarPath?: string;\n userRegisteredAt?: string;\n userNumPosts?: number;\n userNumFollowedBy?: number;\n userNumFollowed?: number;\n}\n\nexport const UserHoverPreviewWrapper: React.FC<\n UserHoverPreviewWrapperProps\n> = ({\n visualStyle,\n iconSize,\n linkText,\n userName,\n userPath,\n userAvatarPath,\n userAvatarAlt,\n userDomainIcon,\n userSmallAvatarPath,\n userRegisteredAt,\n userNumPosts,\n userNumFollowedBy,\n userNumFollowed,\n}) => {\n return (\n \n \n {userSmallAvatarPath ? (\n \n ) : (\n \n )}\n {linkText}\n \n \n );\n};\n\nexport default UserHoverPreviewWrapper;\n","/**\n * Collapsible Section Controls\n *\n * This module contains functions to control collapsible sections with font size controls.\n * Features include:\n * - Toggling between expanded and collapsed view\n * - Increasing and decreasing font size\n */\n\n/**\n * Class representing a collapsible section with font size controls\n */\nclass CollapsibleSection {\n private readonly section: Element;\n private readonly content: HTMLElement;\n private readonly toggleTextElement: Element | null;\n private readonly toggleIconElement: HTMLElement | null;\n private readonly fontDisplayElement: Element | null;\n private readonly baseFontSize: number;\n private readonly initiallyCollapsed: boolean;\n\n /**\n * Create a new collapsible section\n * @param rootElement The root DOM element for this section\n */\n constructor(rootElement: Element) {\n this.section = rootElement;\n this.initiallyCollapsed = rootElement.hasAttribute(\n 'data-initially-collapsed',\n );\n\n // Find and cache all necessary DOM elements\n const contentElement = rootElement.querySelector(\n '[data-collapsable=\"content\"]',\n );\n if (!(contentElement instanceof HTMLElement)) {\n throw new Error(`Section is missing a content element`);\n }\n\n this.content = contentElement;\n\n // Get single elements instead of arrays\n this.toggleTextElement = rootElement.querySelector(\n '[data-collapsable=\"toggle-text\"]',\n );\n\n const iconElement = rootElement.querySelector(\n '[data-collapsable=\"toggle-icon\"]',\n );\n this.toggleIconElement =\n iconElement instanceof HTMLElement ? iconElement : null;\n\n this.fontDisplayElement = rootElement.querySelector(\n '[data-collapsable=\"font-display\"]',\n );\n\n // Initialize font size info\n this.baseFontSize = parseFloat(\n window.getComputedStyle(this.content).fontSize,\n );\n this.updateFontSizeDisplay();\n }\n\n /**\n * Initialize event listeners for this section\n */\n initEventListeners(): void {\n // Setup handlers for all interactive elements\n this.section\n .querySelectorAll('[data-collapsable=\"toggle\"]')\n .forEach((button) => {\n button.addEventListener('click', (e) => {\n e.preventDefault();\n this.toggle();\n });\n });\n\n this.section\n .querySelectorAll('[data-collapsable=\"decrease\"]')\n .forEach((button) => {\n button.addEventListener('click', (e) => {\n e.preventDefault();\n this.decreaseFontSize();\n });\n });\n\n this.section\n .querySelectorAll('[data-collapsable=\"increase\"]')\n .forEach((button) => {\n button.addEventListener('click', (e) => {\n e.preventDefault();\n this.increaseFontSize();\n });\n });\n }\n\n /**\n * Toggle between expanded and collapsed view\n */\n toggle(): void {\n // Determine current state from DOM\n const isCollapsed = this.content.classList.contains('line-clamp-6');\n\n // Toggle line-clamp class\n this.content.classList.toggle('line-clamp-6');\n\n // Update toggle text\n if (this.toggleTextElement) {\n this.toggleTextElement.textContent = isCollapsed\n ? 'Show Less'\n : 'Show More';\n }\n\n // Update toggle icon\n if (this.toggleIconElement) {\n this.toggleIconElement.style.transform = isCollapsed\n ? 'rotate(180deg)'\n : 'rotate(0deg)';\n }\n }\n\n /**\n * Adjust font size of content within min/max bounds\n */\n adjustFontSize(delta: number, min = 12, max = 22): void {\n const currentSize = parseFloat(\n window.getComputedStyle(this.content).fontSize,\n );\n const newSize = Math.min(Math.max(currentSize + delta, min), max);\n\n this.content.style.fontSize = `${newSize}px`;\n this.updateFontSizeDisplay();\n }\n\n /**\n * Increase font size (max 22px)\n */\n increaseFontSize(): void {\n this.adjustFontSize(2);\n }\n\n /**\n * Decrease font size (min 12px)\n */\n decreaseFontSize(): void {\n this.adjustFontSize(-2);\n }\n\n /**\n * Update the font size percentage display\n */\n updateFontSizeDisplay(): void {\n if (!this.fontDisplayElement) return;\n\n const currentSize = parseFloat(\n window.getComputedStyle(this.content).fontSize,\n );\n const percentage = Math.round((currentSize / this.baseFontSize) * 100);\n\n this.fontDisplayElement.textContent = `${percentage}%`;\n }\n}\n\n/**\n * Initialize all collapsible sections on the page\n */\nexport function initCollapsibleSections(): void {\n document\n .querySelectorAll('[data-collapsable=\"root\"]')\n .forEach((sectionElement) => {\n try {\n // Create a new section instance\n const section = new CollapsibleSection(sectionElement);\n\n // Set up event handlers\n section.initEventListeners();\n } catch (error) {\n console.error('Failed to initialize section:', error);\n }\n });\n}\n","export type ValidationResult = {\n isValid: boolean;\n message: string;\n type: 'ipv4' | 'ipv6' | 'cidr-v4' | 'cidr-v6' | 'none';\n};\n\n// Utility functions for IP address validation\nconst isIPv4Segment = (segment: string): boolean => {\n const num = Number(segment);\n return !isNaN(num) && num >= 0 && num <= 255 && segment === num.toString();\n};\n\nconst isIPv4Address = (address: string): boolean => {\n const segments = address.split('.');\n return segments.length === 4 && segments.every(isIPv4Segment);\n};\n\nconst isIPv6Segment = (segment: string): boolean => {\n return segment.length <= 4 && /^[0-9a-fA-F]*$/.test(segment);\n};\n\nconst isIPv6Address = (address: string): boolean => {\n // Handle the :: compression\n const parts = address.split('::');\n if (parts.length > 2) return false; // More than one :: is invalid\n\n if (parts.length === 2) {\n const [left, right] = parts;\n const leftSegments = left ? left.split(':') : [];\n const rightSegments = right ? right.split(':') : [];\n\n // Total segments should be 8 after decompression\n if (leftSegments.length + rightSegments.length > 7) return false;\n\n // Validate each segment\n return (\n leftSegments.every(isIPv6Segment) && rightSegments.every(isIPv6Segment)\n );\n }\n\n // No compression, should be exactly 8 segments\n const segments = address.split(':');\n return segments.length === 8 && segments.every(isIPv6Segment);\n};\n\nconst isCIDRPrefix = (prefix: string, isIPv6: boolean): boolean => {\n const num = Number(prefix);\n return !isNaN(num) && num >= 0 && num <= (isIPv6 ? 128 : 32);\n};\n\nconst validateCIDR = (input: string): ValidationResult | null => {\n const [address, prefix] = input.split('/');\n if (!prefix) return null;\n\n // Check if it's IPv6 CIDR\n if (address.includes(':')) {\n if (!isIPv6Address(address) || !isCIDRPrefix(prefix, true)) {\n return {\n isValid: false,\n message: 'Invalid IPv6 CIDR range format',\n type: 'none',\n };\n }\n return {\n isValid: true,\n message: 'Valid IPv6 CIDR range',\n type: 'cidr-v6',\n };\n }\n\n // Check if it's IPv4 CIDR\n if (!isIPv4Address(address) || !isCIDRPrefix(prefix, false)) {\n return {\n isValid: false,\n message: 'Invalid IPv4 CIDR range format',\n type: 'none',\n };\n }\n return {\n isValid: true,\n message: 'Valid IPv4 CIDR range',\n type: 'cidr-v4',\n };\n};\n\nexport const validateIpAddress = (input: string): ValidationResult => {\n if (!input) {\n return {\n isValid: false,\n message: 'IP address is required',\n type: 'none',\n };\n }\n\n if (input.includes('/')) {\n const cidrResult = validateCIDR(input);\n if (cidrResult) return cidrResult;\n\n return {\n isValid: false,\n message: 'Invalid CIDR range format',\n type: 'none',\n };\n }\n\n // Single IP address validation\n if (isIPv4Address(input)) {\n return {\n isValid: true,\n message: 'Valid IPv4 address',\n type: 'ipv4',\n };\n }\n\n if (isIPv6Address(input)) {\n return {\n isValid: true,\n message: 'Valid IPv6 address',\n type: 'ipv6',\n };\n }\n\n return {\n isValid: false,\n message: 'Invalid IP address format',\n type: 'none',\n };\n};\n","import * as React from 'react';\nimport { useState, useEffect } from 'react';\nimport {\n validateIpAddress,\n type ValidationResult,\n} from '../utils/ipValidation';\n\ninterface IpAddressInputProps {\n initialValue?: string;\n name: string;\n id?: string;\n placeholder?: string;\n onChange?: (value: string, isValid: boolean) => void;\n className?: string;\n}\n\nconst IpAddressInput: React.FC = ({\n initialValue = '',\n name = 'ip_address_role[ip_address]',\n id,\n placeholder = 'Example: 192.168.1.1, 2001:db8::1, or 10.0.0.0/24',\n onChange,\n className = '',\n}) => {\n const [value, setValue] = useState(initialValue);\n const [validation, setValidation] = useState({\n isValid: true,\n message: '',\n type: 'none',\n });\n const [isFocused, setIsFocused] = useState(false);\n\n // Update validation when value changes\n useEffect(() => {\n const result = validateIpAddress(value);\n setValidation(result);\n\n // Call onChange callback if provided\n if (onChange) {\n onChange(value, result.isValid);\n }\n }, [value, onChange]);\n\n // Get border color based on validation state\n const getBorderColorClass = () => {\n if (!isFocused) return 'border-slate-300';\n if (value === '') return 'border-sky-500';\n return validation.isValid ? 'border-emerald-500' : 'border-red-500';\n };\n\n return (\n
\n setValue(e.target.value)}\n onFocus={() => setIsFocused(true)}\n onBlur={() => setIsFocused(false)}\n placeholder={placeholder}\n className={`block w-full rounded-md font-mono shadow-sm focus:ring-sky-500 sm:text-sm ${getBorderColorClass()} ${className}`}\n id={id || 'ip_address_input'}\n />\n\n {/* This is a direct input that will be properly included in form submission */}\n \n\n {/* Validation feedback */}\n {value !== '' && (\n \n
\n {validation.isValid ? (\n \n \n \n ) : (\n \n \n \n )}\n {validation.message}\n
\n
\n )}\n\n {/* Additional helpful information */}\n
\n
\n {validation.type === 'cidr-v4' || validation.type === 'cidr-v6' ? (\n \n CIDR notation represents an IP range (e.g., 10.0.0.0/24 for IPv4\n or 2001:db8::/32 for IPv6)\n \n ) : (\n \n Enter a single IP address (IPv4: 192.168.1.1 or IPv6: 2001:db8::1)\n or an IP range in CIDR notation\n \n )}\n
\n
\n \n );\n};\n\nexport default IpAddressInput;\n","import ReactOnRails from 'react-on-rails';\n\nimport UserSearchBar from '../bundles/Main/components/UserSearchBar';\nimport { UserMenu } from '../bundles/Main/components/UserMenu';\nimport { PostHoverPreviewWrapper } from '../bundles/Main/components/PostHoverPreviewWrapper';\nimport { UserHoverPreviewWrapper } from '../bundles/Main/components/UserHoverPreviewWrapper';\nimport { initCollapsibleSections } from '../bundles/UI/collapsibleSections';\nimport { IpAddressInput } from '../bundles/UI/components';\n\n// This is how react_on_rails can see the components in the browser.\nReactOnRails.register({\n UserSearchBar,\n UserMenu,\n PostHoverPreviewWrapper,\n UserHoverPreviewWrapper,\n IpAddressInput,\n});\n\n// Initialize collapsible sections\ndocument.addEventListener('DOMContentLoaded', function () {\n initCollapsibleSections();\n});\n","import * as React from 'react';\nimport { useRef, useEffect, useState } from 'react';\n\ninterface UserMenuProps {\n userEmail: string;\n userRole?: 'admin' | 'moderator';\n editProfilePath: string;\n signOutPath: string;\n csrfToken: string;\n globalStatesPath: string;\n goodJobPath: string;\n grafanaPath: string;\n prometheusPath: string;\n}\n\nexport const UserMenu: React.FC = ({\n userEmail,\n userRole,\n editProfilePath,\n signOutPath,\n csrfToken,\n globalStatesPath,\n goodJobPath,\n grafanaPath,\n prometheusPath,\n}) => {\n const [isOpen, setIsOpen] = useState(false);\n const menuRef = useRef(null);\n\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (menuRef.current && !menuRef.current.contains(event.target as Node)) {\n setIsOpen(false);\n }\n };\n\n document.addEventListener('mousedown', handleClickOutside);\n return () => document.removeEventListener('mousedown', handleClickOutside);\n }, []);\n\n const handleSignOut = (e: React.FormEvent) => {\n e.preventDefault();\n const form = document.createElement('form');\n form.method = 'POST';\n form.action = signOutPath;\n form.style.display = 'none';\n\n const methodInput = document.createElement('input');\n methodInput.type = 'hidden';\n methodInput.name = '_method';\n methodInput.value = 'delete';\n\n const csrfInput = document.createElement('input');\n csrfInput.type = 'hidden';\n csrfInput.name = 'authenticity_token';\n csrfInput.value = csrfToken;\n\n form.appendChild(methodInput);\n form.appendChild(csrfInput);\n document.body.appendChild(form);\n form.submit();\n };\n\n return (\n
\n setIsOpen(!isOpen)}\n >\n \n \n \n\n \n
\n
{userEmail}
\n {userRole === 'admin' && (\n \n Admin\n \n )}\n {userRole === 'moderator' && (\n \n Mod\n \n )}\n
\n\n {userRole === 'admin' && (\n <>\n \n \n Global State\n \n \n \n Jobs Queue\n \n \n \n Grafana\n \n \n \n Prometheus\n \n \n )}\n\n \n \n Edit Profile\n \n\n \n \n Sign Out\n \n
\n \n );\n};\n"],"names":["Icon","props","type","className","React","xmlns","fill","viewBox","strokeWidth","d","version","attributeType","attributeName","from","to","dur","repeatCount","stroke","strokeLinecap","strokeLinejoin","COMMON_LIST_ELEM_CLASSES","ListItem","value","thumb","isLast","selected","style","href","subtext","domainIcon","textClassName","filter","Boolean","onPointerUp","window","location","join","src","alt","CONFIG","STYLES","LIST_ELEM_CLASSNAME","SVG_BASE_CLASSNAME","SVG_FOCUSABLE_CLASSNAME","INPUT_CLASSNAME","log","info","args","console","error","iconClassNamesForSize","size","getPreviewContainerClassName","maxWidth","maxHeight","innerWidth","getHeaderFooterClassName","getAvatarImageClassName","small","medium","large","useHoverPreview","showPreview","setShowPreview","useState","previewStyle","setPreviewStyle","containerRef","useRef","previewRef","portalContainer","useMemo","document","createElement","useEffect","body","appendChild","removeChild","updatePosition","newPosition","calculatePreviewPosition","current","linkRect","getBoundingClientRect","previewRect","viewport","innerHeight","showOnRight","right","left","linkCenter","top","height","padding","parseInt","getComputedStyle","documentElement","fontSize","position","zIndex","overflow","transition","addEventListener","removeEventListener","handleMouseEnter","opacity","setTimeout","handleMouseLeave","anchorClassNamesForVisualStyle","visualStyle","hasIcon","classNames","push","HoverPreview","children","previewContent","previewClassName","ref","onMouseEnter","onMouseLeave","createPortal","PostHoverPreview","postTitle","postThumbnailPath","postThumbnailAlt","postDomainIcon","creatorName","creatorAvatarPath","Image","postHeaderFooterClassName","title","loading","PostHoverPreviewWrapper","linkText","postPath","UserHoverPreview","userName","userAvatarPath","userAvatarAlt","userDomainIcon","userRegisteredAt","userNumPosts","userNumFollowedBy","userNumFollowed","UserHoverPreviewWrapper","iconSize","userPath","userSmallAvatarPath","CollapsibleSection","constructor","rootElement","this","section","initiallyCollapsed","hasAttribute","contentElement","querySelector","HTMLElement","Error","content","toggleTextElement","iconElement","toggleIconElement","fontDisplayElement","baseFontSize","parseFloat","updateFontSizeDisplay","initEventListeners","querySelectorAll","forEach","button","e","preventDefault","toggle","decreaseFontSize","increaseFontSize","isCollapsed","classList","contains","textContent","transform","adjustFontSize","delta","min","max","currentSize","newSize","Math","percentage","round","isIPv4Segment","segment","num","Number","isNaN","toString","isIPv4Address","address","segments","split","length","every","isIPv6Segment","test","isIPv6Address","parts","leftSegments","rightSegments","isCIDRPrefix","prefix","isIPv6","validateIpAddress","input","isValid","message","includes","cidrResult","validateCIDR","IpAddressInput","initialValue","name","id","placeholder","onChange","setValue","validation","setValidation","isFocused","setIsFocused","result","target","onFocus","onBlur","readOnly","display","fillRule","clipRule","ReactOnRails","UserSearchBar","isServerRendered","pendingRequest","setPendingRequest","state","setState","userList","selectedIdx","errorMessage","typingSettled","inputRef","clearResults","useCallback","s","cancelPendingRequest","async","abort","sendSearchRequest","controller","AbortController","req","fetch","signal","status","error_json","json","JSON","stringify","gotUserList","users","err","sendRequest","searchForUser","isEmpty","searchForUserDebounced","debounce","invokeSelected","idx","user","show_path","invokeIdx","visibility","items","anyShown","Object","values","some","UserSearchBarItems","key","map","num_posts","domain_icon","keyHandlers","Tab","shiftKey","selectPrevListElem","selectNextListElem","ArrowDown","ArrowUp","Enter","setNewIdxTruncated","newIdx","autoFocus","defaultValue","onKeyDown","event","handler","code","UserMenu","userEmail","userRole","editProfilePath","signOutPath","csrfToken","globalStatesPath","goodJobPath","grafanaPath","prometheusPath","isOpen","setIsOpen","menuRef","handleClickOutside","onClick","form","method","action","methodInput","csrfInput","submit","sectionElement"],"sourceRoot":""}