import { Trans, useLingui } from '@lingui/react/macro'; import { MenuDivider, MenuItem } from '@szhsin/react-menu'; import { getBlurHashAverageColor } from 'fast-blurhash'; import { useEffect, useLayoutEffect, useMemo, useRef, useState, } from 'preact/hooks'; import { useHotkeys } from 'react-hotkeys-hook'; import { oklch2rgb, rgb2oklch } from '../utils/color-utils'; import isRTL from '../utils/is-rtl'; import showToast from '../utils/show-toast'; import states from '../utils/states'; import store from '../utils/store'; import Icon from './icon'; import Link from './link'; import Media from './media'; import MenuLink from './menu-link'; import Menu2 from './menu2'; const { PHANPY_IMG_ALT_API_URL: IMG_ALT_API_URL } = import.meta.env; function MediaModal({ mediaAttachments, statusID, instance, lang, index = 0, onClose = () => {}, }) { const { t } = useLingui(); const [uiState, setUIState] = useState('default'); const carouselRef = useRef(null); const [currentIndex, setCurrentIndex] = useState(index); const carouselFocusItem = useRef(null); useLayoutEffect(() => { carouselFocusItem.current?.scrollIntoView(); // history.pushState({ mediaModal: true }, ''); // const handlePopState = (e) => { // if (e.state?.mediaModal) { // onClose(); // } // }; // window.addEventListener('popstate', handlePopState); // return () => { // window.removeEventListener('popstate', handlePopState); // }; }, []); const prevStatusID = useRef(statusID); useEffect(() => { const scrollLeft = index * carouselRef.current.clientWidth; const differentStatusID = prevStatusID.current !== statusID; if (differentStatusID) prevStatusID.current = statusID; carouselRef.current.focus(); carouselRef.current.scrollTo({ left: scrollLeft * (isRTL() ? -1 : 1), behavior: differentStatusID ? 'auto' : 'smooth', }); }, [index, statusID]); const [showControls, setShowControls] = useState(true); useEffect(() => { let handleSwipe = () => { onClose(); }; if (carouselRef.current) { carouselRef.current.addEventListener('swiped-down', handleSwipe); } return () => { if (carouselRef.current) { carouselRef.current.removeEventListener('swiped-down', handleSwipe); } }; }, []); useHotkeys( 'esc', onClose, { ignoreEventWhen: (e) => { const hasModal = !!document.querySelector('#modal-container > *'); return hasModal; }, }, [onClose], ); useEffect(() => { let handleScroll = () => { const { clientWidth, scrollLeft } = carouselRef.current; const index = Math.round(Math.abs(scrollLeft) / clientWidth); setCurrentIndex(index); }; if (carouselRef.current) { carouselRef.current.addEventListener('scroll', handleScroll, { passive: true, }); } return () => { if (carouselRef.current) { carouselRef.current.removeEventListener('scroll', handleScroll); } }; }, []); useEffect(() => { let timer = setTimeout(() => { carouselRef.current?.focus?.(); }, 100); return () => clearTimeout(timer); }, []); const mediaOkColors = useMemo(() => { return mediaAttachments?.map((media) => { const { blurhash } = media; if (blurhash) { const averageColor = getBlurHashAverageColor(blurhash); return rgb2oklch(averageColor); } return null; }); }, [mediaAttachments]); const mediaAccentColors = useMemo(() => { return mediaOkColors?.map((okColor) => { if (okColor) { return { light: oklch2rgb([0.95, 0.01, okColor[2]]), dark: oklch2rgb([0.35, 0.01, okColor[2]]), default: oklch2rgb([0.6, okColor[1], okColor[2]]), }; } return null; }); }); const mediaAccentGradients = useMemo(() => { const gap = 5; const range = 100 / mediaAccentColors.length; const colors = mediaAccentColors.map((color, i) => { const start = i * range + gap; const end = (i + 1) * range - gap; if (color?.light && color?.dark) { return { light: ` rgb(${color.light?.join(',')}) ${start}%, rgb(${color.light?.join(',')}) ${end}% `, dark: ` rgb(${color.dark?.join(',')}) ${start}%, rgb(${color.dark?.join(',')}) ${end}% `, }; } return { light: ` transparent ${start}%, transparent ${end}% `, dark: ` transparent ${start}%, transparent ${end}% `, }; }); const lightGradient = colors.map((color) => color.light).join(', '); const darkGradient = colors.map((color) => color.dark).join(', '); return { light: lightGradient, dark: darkGradient, }; }, [mediaAccentColors]); let toastRef = useRef(null); useEffect(() => { return () => { toastRef.current?.hideToast?.(); }; }, []); useLayoutEffect(() => { const currentColor = mediaAccentColors[currentIndex]; let $meta; let metaColor; if (currentColor) { const theme = store.local.get('theme'); if (theme) { const mediaColor = `rgb(${currentColor[theme].join(',')})`; console.log({ mediaColor }); $meta = document.querySelector( `meta[name="theme-color"][data-theme-setting="manual"]`, ); if ($meta) { metaColor = $meta.content; $meta.content = mediaColor; } } else { const colorScheme = window.matchMedia('(prefers-color-scheme: dark)') .matches ? 'dark' : 'light'; const mediaColor = `rgb(${currentColor[colorScheme].join(',')})`; console.log({ mediaColor }); $meta = document.querySelector( `meta[name="theme-color"][media*="${colorScheme}"]`, ); if ($meta) { metaColor = $meta.content; $meta.content = mediaColor; } } } return () => { // Reset meta color if ($meta && metaColor) { $meta.content = metaColor; } }; }, [currentIndex, mediaAccentColors]); return (