{"version":3,"sources":["webpack:///app/javascript/opt/mastodon/app/javascript/flavours/glitch/features/account_gallery/components/media_item.tsx","webpack:///app/javascript/opt/mastodon/app/javascript/flavours/glitch/features/account_gallery/index.tsx"],"names":["MediaItem","_ref","attachment","onOpenMedia","account","useAppSelector","state","accounts","get","getIn","visible","setVisible","useState","displayMedia","loaded","setLoaded","handleImageLoad","useCallback","handleMouseEnter","e","target","HTMLVideoElement","play","handleMouseLeave","pause","currentTime","handleClick","button","ctrlKey","metaKey","preventDefault","status","description","previewUrl","fullUrl","avatarUrl","avatar_static","lang","blurhash","statusUrl","type","thumbnail","badges","length","push","_jsx","AltTextBadge","_jsxs","_Fragment","children","src","alt","title","onLoad","className","Icon","id","icon","HeadphonesIcon","x","y","style","objectPosition","includes","duration","onMouseEnter","onMouseLeave","onLoadedData","autoPlay","autoPlayGif","playsInline","loop","muted","MovieIcon","formatTime","Math","floor","VisibilityOffIcon","Blurhash","hash","classNames","dummy","useBlurhash","href","onClick","rel","messages","defineMessages","profile","defaultMessage","getAccountGallery","createSelector","accountId","timelines","ImmutableList","statuses","statusIds","items","forEach","statusId","concat","map","media","set","RemoteHint","acct","url","domain","split","undefined","TimelineHint","message","FormattedMessage","label","values","AccountGallery","_ref2","_attachments$last","multiColumn","intl","useIntl","useParams","dispatch","useAppDispatch","accounts_map","normalizeForLookup","attachments","isLoading","hasMore","blockedBy","relationships","suspended","isAccount","remote","username","hidden","getAccountHidden","maxId","last","useEffect","lookupAccount","fetchAccount","expandAccountMediaTimeline","handleLoadMore","handleOpenMedia","openModal","modalType","modalProps","options","index","findIndex","BundleColumnError","errorType","emptyMessage","LimitedAccountHint","isEmpty","forceEmptyState","Column","iconComponent","PersonIcon","heading","formatMessage","alwaysShowBackButton","ScrollableList","prepend","AccountHeader","hideTabs","alwaysPrepend","append","scrollKey","onLoadMore","bindToDocument"],"mappings":"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","file":"js/flavours/glitch/async/account_gallery-22991a9e51fe2204776a.chunk.js","sourcesContent":["import { useState, useCallback } from 'react';\n\nimport classNames from 'classnames';\n\nimport HeadphonesIcon from '@/material-icons/400-24px/headphones-fill.svg?react';\nimport MovieIcon from '@/material-icons/400-24px/movie-fill.svg?react';\nimport VisibilityOffIcon from '@/material-icons/400-24px/visibility_off.svg?react';\nimport { AltTextBadge } from 'flavours/glitch/components/alt_text_badge';\nimport { Blurhash } from 'flavours/glitch/components/blurhash';\nimport { Icon } from 'flavours/glitch/components/icon';\nimport { formatTime } from 'flavours/glitch/features/video';\nimport {\n autoPlayGif,\n displayMedia,\n useBlurhash,\n} from 'flavours/glitch/initial_state';\nimport type { Status, MediaAttachment } from 'flavours/glitch/models/status';\nimport { useAppSelector } from 'flavours/glitch/store';\n\nexport const MediaItem: React.FC<{\n attachment: MediaAttachment;\n onOpenMedia: (arg0: MediaAttachment) => void;\n}> = ({ attachment, onOpenMedia }) => {\n const account = useAppSelector((state) =>\n state.accounts.get(attachment.getIn(['status', 'account']) as string),\n );\n const [visible, setVisible] = useState(\n (displayMedia !== 'hide_all' &&\n !attachment.getIn(['status', 'sensitive'])) ||\n displayMedia === 'show_all',\n );\n const [loaded, setLoaded] = useState(false);\n\n const handleImageLoad = useCallback(() => {\n setLoaded(true);\n }, [setLoaded]);\n\n const handleMouseEnter = useCallback(\n (e: React.MouseEvent<HTMLVideoElement>) => {\n if (e.target instanceof HTMLVideoElement) {\n void e.target.play();\n }\n },\n [],\n );\n\n const handleMouseLeave = useCallback(\n (e: React.MouseEvent<HTMLVideoElement>) => {\n if (e.target instanceof HTMLVideoElement) {\n e.target.pause();\n e.target.currentTime = 0;\n }\n },\n [],\n );\n\n const handleClick = useCallback(\n (e: React.MouseEvent<HTMLAnchorElement>) => {\n if (e.button === 0 && !(e.ctrlKey || e.metaKey)) {\n e.preventDefault();\n\n if (visible) {\n onOpenMedia(attachment);\n } else {\n setVisible(true);\n }\n }\n },\n [attachment, visible, onOpenMedia, setVisible],\n );\n\n const status = attachment.get('status') as Status;\n const description = (attachment.getIn(['translation', 'description']) ||\n attachment.get('description')) as string | undefined;\n const previewUrl = attachment.get('preview_url') as string;\n const fullUrl = attachment.get('url') as string;\n const avatarUrl = account?.avatar_static;\n const lang = status.get('language') as string;\n const blurhash = attachment.get('blurhash') as string;\n const statusUrl = status.get('url') as string;\n const type = attachment.get('type') as string;\n\n let thumbnail;\n\n const badges = [];\n\n if (description && description.length > 0) {\n badges.push(<AltTextBadge key='alt' description={description} />);\n }\n\n if (!visible) {\n thumbnail = (\n <div className='media-gallery__item__overlay'>\n <Icon id='eye-slash' icon={VisibilityOffIcon} />\n </div>\n );\n } else if (type === 'audio') {\n thumbnail = (\n <>\n <img\n src={previewUrl || avatarUrl}\n alt={description}\n title={description}\n lang={lang}\n onLoad={handleImageLoad}\n />\n\n <div className='media-gallery__item__overlay media-gallery__item__overlay--corner'>\n <Icon id='music' icon={HeadphonesIcon} />\n </div>\n </>\n );\n } else if (type === 'image') {\n const focusX = (attachment.getIn(['meta', 'focus', 'x']) || 0) as number;\n const focusY = (attachment.getIn(['meta', 'focus', 'y']) || 0) as number;\n const x = (focusX / 2 + 0.5) * 100;\n const y = (focusY / -2 + 0.5) * 100;\n\n thumbnail = (\n <img\n src={previewUrl}\n alt={description}\n title={description}\n lang={lang}\n style={{ objectPosition: `${x}% ${y}%` }}\n onLoad={handleImageLoad}\n />\n );\n } else if (['video', 'gifv'].includes(type)) {\n const duration = attachment.getIn([\n 'meta',\n 'original',\n 'duration',\n ]) as number;\n\n thumbnail = (\n <div className='media-gallery__gifv'>\n <video\n className='media-gallery__item-gifv-thumbnail'\n aria-label={description}\n title={description}\n lang={lang}\n src={fullUrl}\n onMouseEnter={handleMouseEnter}\n onMouseLeave={handleMouseLeave}\n onLoadedData={handleImageLoad}\n autoPlay={autoPlayGif}\n playsInline\n loop\n muted\n />\n\n {type === 'video' && (\n <div className='media-gallery__item__overlay media-gallery__item__overlay--corner'>\n <Icon id='play' icon={MovieIcon} />\n </div>\n )}\n </div>\n );\n\n if (type === 'gifv') {\n badges.push(\n <span\n key='gif'\n className='media-gallery__alt__label media-gallery__alt__label--non-interactive'\n >\n GIF\n </span>,\n );\n } else {\n badges.push(\n <span\n key='video'\n className='media-gallery__alt__label media-gallery__alt__label--non-interactive'\n >\n {formatTime(Math.floor(duration))}\n </span>,\n );\n }\n }\n\n return (\n <div className='media-gallery__item media-gallery__item--square'>\n <Blurhash\n hash={blurhash}\n className={classNames('media-gallery__preview', {\n 'media-gallery__preview--hidden': visible && loaded,\n })}\n dummy={!useBlurhash}\n />\n\n <a\n className='media-gallery__item-thumbnail'\n href={statusUrl}\n onClick={handleClick}\n target='_blank'\n rel='noopener noreferrer'\n >\n {thumbnail}\n </a>\n\n {badges.length > 0 && (\n <div className='media-gallery__item__badges'>{badges}</div>\n )}\n </div>\n );\n};\n","import { useEffect, useCallback } from 'react';\n\nimport { FormattedMessage, useIntl, defineMessages } from 'react-intl';\n\nimport { useParams } from 'react-router-dom';\n\nimport { createSelector } from '@reduxjs/toolkit';\nimport type { Map as ImmutableMap } from 'immutable';\nimport { List as ImmutableList } from 'immutable';\n\nimport PersonIcon from '@/material-icons/400-24px/person.svg?react';\nimport { lookupAccount, fetchAccount } from 'flavours/glitch/actions/accounts';\nimport { openModal } from 'flavours/glitch/actions/modal';\nimport { expandAccountMediaTimeline } from 'flavours/glitch/actions/timelines';\nimport ScrollableList from 'flavours/glitch/components/scrollable_list';\nimport { TimelineHint } from 'flavours/glitch/components/timeline_hint';\nimport { AccountHeader } from 'flavours/glitch/features/account_timeline/components/account_header';\nimport { LimitedAccountHint } from 'flavours/glitch/features/account_timeline/components/limited_account_hint';\nimport BundleColumnError from 'flavours/glitch/features/ui/components/bundle_column_error';\nimport Column from 'flavours/glitch/features/ui/components/column';\nimport type { MediaAttachment } from 'flavours/glitch/models/media_attachment';\nimport { normalizeForLookup } from 'flavours/glitch/reducers/accounts_map';\nimport { getAccountHidden } from 'flavours/glitch/selectors/accounts';\nimport type { RootState } from 'flavours/glitch/store';\nimport { useAppSelector, useAppDispatch } from 'flavours/glitch/store';\n\nimport { MediaItem } from './components/media_item';\n\nconst messages = defineMessages({\n profile: { id: 'column_header.profile', defaultMessage: 'Profile' },\n});\n\nconst getAccountGallery = createSelector(\n [\n (state: RootState, accountId: string) =>\n (state.timelines as ImmutableMap<string, unknown>).getIn(\n [`account:${accountId}:media`, 'items'],\n ImmutableList(),\n ) as ImmutableList<string>,\n (state: RootState) => state.statuses,\n ],\n (statusIds, statuses) => {\n let items = ImmutableList<MediaAttachment>();\n\n statusIds.forEach((statusId) => {\n const status = statuses.get(statusId) as\n | ImmutableMap<string, unknown>\n | undefined;\n\n if (status) {\n items = items.concat(\n (\n status.get('media_attachments') as ImmutableList<MediaAttachment>\n ).map((media) => media.set('status', status)),\n );\n }\n });\n\n return items;\n },\n);\n\ninterface Params {\n acct?: string;\n id?: string;\n}\n\nconst RemoteHint: React.FC<{\n accountId: string;\n}> = ({ accountId }) => {\n const account = useAppSelector((state) => state.accounts.get(accountId));\n const acct = account?.acct;\n const url = account?.url;\n const domain = acct ? acct.split('@')[1] : undefined;\n\n if (!url) {\n return null;\n }\n\n return (\n <TimelineHint\n url={url}\n message={\n <FormattedMessage\n id='hints.profiles.posts_may_be_missing'\n defaultMessage='Some posts from this profile may be missing.'\n />\n }\n label={\n <FormattedMessage\n id='hints.profiles.see_more_posts'\n defaultMessage='See more posts on {domain}'\n values={{ domain: <strong>{domain}</strong> }}\n />\n }\n />\n );\n};\n\nexport const AccountGallery: React.FC<{\n multiColumn: boolean;\n}> = ({ multiColumn }) => {\n const intl = useIntl();\n const { acct, id } = useParams<Params>();\n const dispatch = useAppDispatch();\n const accountId = useAppSelector(\n (state) =>\n id ??\n (state.accounts_map.get(normalizeForLookup(acct)) as string | undefined),\n );\n const attachments = useAppSelector((state) =>\n accountId\n ? getAccountGallery(state, accountId)\n : ImmutableList<MediaAttachment>(),\n );\n const isLoading = useAppSelector((state) =>\n (state.timelines as ImmutableMap<string, unknown>).getIn([\n `account:${accountId}:media`,\n 'isLoading',\n ]),\n );\n const hasMore = useAppSelector((state) =>\n (state.timelines as ImmutableMap<string, unknown>).getIn([\n `account:${accountId}:media`,\n 'hasMore',\n ]),\n );\n const account = useAppSelector((state) =>\n accountId ? state.accounts.get(accountId) : undefined,\n );\n const blockedBy = useAppSelector(\n (state) =>\n state.relationships.getIn([accountId, 'blocked_by'], false) as boolean,\n );\n const suspended = useAppSelector(\n (state) => state.accounts.getIn([accountId, 'suspended'], false) as boolean,\n );\n const isAccount = !!account;\n const remote = account?.acct !== account?.username;\n const hidden = useAppSelector((state) =>\n accountId ? getAccountHidden(state, accountId) : false,\n );\n const maxId = attachments.last()?.getIn(['status', 'id']) as\n | string\n | undefined;\n\n useEffect(() => {\n if (!accountId) {\n dispatch(lookupAccount(acct));\n }\n }, [dispatch, accountId, acct]);\n\n useEffect(() => {\n if (accountId && !isAccount) {\n dispatch(fetchAccount(accountId));\n }\n\n if (accountId && isAccount) {\n void dispatch(expandAccountMediaTimeline(accountId));\n }\n }, [dispatch, accountId, isAccount]);\n\n const handleLoadMore = useCallback(() => {\n if (maxId) {\n void dispatch(expandAccountMediaTimeline(accountId, { maxId }));\n }\n }, [dispatch, accountId, maxId]);\n\n const handleOpenMedia = useCallback(\n (attachment: MediaAttachment) => {\n const statusId = attachment.getIn(['status', 'id']);\n const lang = attachment.getIn(['status', 'language']);\n\n if (attachment.get('type') === 'video') {\n dispatch(\n openModal({\n modalType: 'VIDEO',\n modalProps: {\n media: attachment,\n statusId,\n lang,\n options: { autoPlay: true },\n },\n }),\n );\n } else if (attachment.get('type') === 'audio') {\n dispatch(\n openModal({\n modalType: 'AUDIO',\n modalProps: {\n media: attachment,\n statusId,\n lang,\n options: { autoPlay: true },\n },\n }),\n );\n } else {\n const media = attachment.getIn([\n 'status',\n 'media_attachments',\n ]) as ImmutableList<MediaAttachment>;\n const index = media.findIndex(\n (x) => x.get('id') === attachment.get('id'),\n );\n\n dispatch(\n openModal({\n modalType: 'MEDIA',\n modalProps: { media, index, statusId, lang },\n }),\n );\n }\n },\n [dispatch],\n );\n\n if (accountId && !isAccount) {\n return <BundleColumnError multiColumn={multiColumn} errorType='routing' />;\n }\n\n let emptyMessage;\n\n if (accountId) {\n if (suspended) {\n emptyMessage = (\n <FormattedMessage\n id='empty_column.account_suspended'\n defaultMessage='Account suspended'\n />\n );\n } else if (hidden) {\n emptyMessage = <LimitedAccountHint accountId={accountId} />;\n } else if (blockedBy) {\n emptyMessage = (\n <FormattedMessage\n id='empty_column.account_unavailable'\n defaultMessage='Profile unavailable'\n />\n );\n } else if (remote && attachments.isEmpty()) {\n emptyMessage = <RemoteHint accountId={accountId} />;\n } else {\n emptyMessage = (\n <FormattedMessage\n id='empty_column.account_timeline'\n defaultMessage='No posts found'\n />\n );\n }\n }\n\n const forceEmptyState = suspended || blockedBy || hidden;\n\n return (\n <Column\n icon='user-circle'\n iconComponent={PersonIcon}\n heading={intl.formatMessage(messages.profile)}\n alwaysShowBackButton\n >\n <ScrollableList\n className='account-gallery__container'\n prepend={\n accountId && (\n <AccountHeader accountId={accountId} hideTabs={forceEmptyState} />\n )\n }\n alwaysPrepend\n append={remote && accountId && <RemoteHint accountId={accountId} />}\n scrollKey='account_gallery'\n isLoading={isLoading}\n hasMore={!forceEmptyState && hasMore}\n onLoadMore={handleLoadMore}\n emptyMessage={emptyMessage}\n bindToDocument={!multiColumn}\n >\n {attachments.map((attachment) => (\n <MediaItem\n key={attachment.get('id') as string}\n attachment={attachment}\n onOpenMedia={handleOpenMedia}\n />\n ))}\n </ScrollableList>\n </Column>\n );\n};\n\n// eslint-disable-next-line import/no-default-export\nexport default AccountGallery;\n"],"sourceRoot":""}