import { Box, VStack, HStack, SpanBox } from '../../elements/LayoutPrimitives' import { LabelChip } from '../../elements/LabelChip' import type { LinkedItemCardProps } from './CardTypes' import { useCallback, useState } from 'react' import { AuthorInfoStyle, CardCheckbox, LibraryItemMetadata, MetaStyle, siteName, TitleStyle, MenuStyle, FLAIR_ICON_NAMES, } from './LibraryCardStyles' import { sortedLabels } from '../../../lib/labelsSort' import { LIBRARY_LEFT_MENU_WIDTH } from '../../templates/navMenu/LibraryMenu' import { LibraryHoverActions } from './LibraryHoverActions' import { useHover, useFloating, useInteractions, size, offset, autoUpdate, } from '@floating-ui/react' import { CardMenu } from '../CardMenu' import { DotsThree } from '@phosphor-icons/react' import { isTouchScreenDevice } from '../../../lib/deviceType' import { CoverImage } from '../../elements/CoverImage' import { ProgressBar } from '../../elements/ProgressBar' import { theme } from '../../tokens/stitches.config' import { ListFallbackImage } from './FallbackImage' import { useRouter } from 'next/router' import { LoadingBar } from '../../elements/LoadingBar' export function LibraryListCard(props: LinkedItemCardProps): JSX.Element { const router = useRouter() const [isOpen, setIsOpen] = useState(false) const { refs, floatingStyles, context } = useFloating({ open: isOpen, onOpenChange: setIsOpen, middleware: [ offset({ mainAxis: -25, }), size(), ], placement: 'top-end', whileElementsMounted: autoUpdate, }) const hover = useHover(context) const { getReferenceProps, getFloatingProps } = useInteractions([hover]) const layoutWidths = props.legacyLayout ? { width: '100vw', '@media (min-width: 768px)': { width: `calc(100vw - ${LIBRARY_LEFT_MENU_WIDTH})`, }, '@media (min-width: 930px)': { width: '580px', }, '@media (min-width: 1280px)': { width: '890px', }, '@media (min-width: 1600px)': { width: '1200px', }, } : { width: '100%', } return ( { if (props.multiSelectMode !== 'off') { props.setIsChecked(props.item.id, !props.isChecked) return } window.localStorage.setItem('nav-return', router.asPath) if (event.metaKey || event.ctrlKey) { window.open( `/${props.viewer.profile.username}/${props.item.slug}`, '_blank' ) } else { router.push(`/${props.viewer.profile.username}/${props.item.slug}`) } }} > {!isTouchScreenDevice() && props.multiSelectMode == 'off' && ( )} ) } type LoadingBarOverlayProps = { top: number width: string bottomRadius: string fillColor?: string percentFill?: number } type ProgressBarOverlayProps = { top: number width: string value: number bottomRadius: string } export const LoadingBarOverlay = ( props: LoadingBarOverlayProps ): JSX.Element => { return ( ) } export const ProgressBarOverlay = ( props: ProgressBarOverlayProps ): JSX.Element => { return ( ) } type ListImageProps = { src?: string title?: string readingProgress?: number isLoading?: boolean } const ListImage = (props: ListImageProps): JSX.Element => { const [displayFallback, setDisplayFallback] = useState(props.src == undefined) return ( <> {props.isLoading && ( )} {(props.readingProgress ?? 0) > 0 && !props.isLoading && ( )} {displayFallback ? ( ) : ( { setDisplayFallback(true) }} /> )} ) } export function LibraryListCardContent( props: LinkedItemCardProps ): JSX.Element { const [menuOpen, setMenuOpen] = useState(false) const { isChecked, setIsChecked, item } = props const originText = siteName( props.item.originalArticleUrl, props.item.url, props.item.siteName ) const handleCheckChanged = useCallback(() => { setIsChecked(item.id, !isChecked) }, [isChecked, setIsChecked, item]) return ( input': { p: '0px', m: '0px', }, }} > setMenuOpen(open)} actionHandler={props.handleAction} triggerElement={ } /> {props.item.title} {(props.item.author?.length ?? 0 + originText.length) > 0 && ( {props.item.author} {props.item.author && originText && ' | '} {originText} )} {sortedLabels(props.item.labels) .filter( ({ name }) => FLAIR_ICON_NAMES.indexOf(name.toLocaleLowerCase()) == -1 ) .map(({ name, color }, index) => ( ))} ) }