import classNames from "classnames"; import { RefObject, MouseEventHandler, useEffect, useLayoutEffect, useRef } from "react"; import { sortable } from "react-anything-sortable"; import { useTranslation } from "react-i18next"; import styled, { useTheme } from "styled-components"; import Box from "../../Styled/Box"; import { RawButton } from "../../Styled/Button"; import Icon, { StyledIcon } from "../../Styled/Icon"; import Ul from "../../Styled/List"; import Spacing from "../../Styled/Spacing"; import Text, { TextSpan } from "../../Styled/Text"; import parseCustomHtmlToReact from "../Custom/parseCustomHtmlToReact"; export interface Story { title: string; text: string; id: string; shareData?: any; } interface Props { story: Story; editStory: () => void; viewStory: () => void; deleteStory: () => void; recaptureStory: () => void; recaptureStorySuccessful: boolean; menuOpen: boolean; openMenu: () => void; closeMenu: () => void; parentRef: any; index: number; //props for react-anything-sortable className: any; style: any; onMouseDown(): void; onTouchStart(): void; } interface MenuProps extends Props { storyRef: RefObject; } const findTextContent = (content: any): string => { if (typeof content === "string") { return content; } if (content[0] && content[0].props && content[0].props.children) { return findTextContent(content[0].props.children); } if (!content.props || !content.props.children) { return ""; } if (typeof content.props.children === "string") { return content.props.children; } return findTextContent(content.props.children); }; const StoryControl = styled(Box).attrs({ centered: true, left: true, justifySpaceBetween: true })``; const StoryMenuButton = styled(RawButton)` color: ${(props) => props.theme.textDarker}; background-color: ${(props) => props.theme.textLight}; ${StyledIcon} { width: 35px; } svg { fill: ${(props) => props.theme.textDarker}; width: 18px; height: 18px; } border-radius: 0; width: 124px; // ensure we support long strings min-height: 32px; display: block; &:hover, &:focus { color: ${(props) => props.theme.textLight}; background-color: ${(props) => props.theme.colorPrimary}; svg { fill: ${(props) => props.theme.textLight}; stroke: ${(props) => props.theme.textLight}; } } `; const hideList = (props: Props) => props.closeMenu(); const getTruncatedContent = (text: string) => { const content = parseCustomHtmlToReact(text); const except = findTextContent(content); return except.slice(0, 100); }; const toggleMenu = (props: Props): MouseEventHandler => (event) => { event.stopPropagation(); props.openMenu(); }; const viewStory = (props: Props): MouseEventHandler => (event) => { event.stopPropagation(); props.viewStory(); hideList(props); }; const deleteStory = (props: Props): MouseEventHandler => (event) => { event.stopPropagation(); props.deleteStory(); hideList(props); }; const editStory = (props: Props): MouseEventHandler => (event) => { event.stopPropagation(); props.editStory(); hideList(props); }; const recaptureStory = (props: Props): MouseEventHandler => (event) => { event.stopPropagation(); props.recaptureStory(); hideList(props); }; const StoryMenu = (props: MenuProps) => { const { t } = useTranslation(); const menuRef = useRef(null); useLayoutEffect(() => { // Adjust the position of the menu so it stays inside the scroll container. if (!menuRef.current) return; if (!props.parentRef.current) return; // Grow downwards, by default: Object.assign(menuRef.current.style, { top: "0px", bottom: "unset" }); const selfRect = menuRef.current.getBoundingClientRect(); const parentRect = props.parentRef.current.getBoundingClientRect(); if (selfRect.bottom > parentRect.bottom) { // Looks like there's no room to the bottom; grow upwards. Object.assign(menuRef.current.style, { top: "unset", bottom: "0px" }); } }, [props.parentRef]); return (
  • {t("story.view")}
  • {t("story.edit")}
  • {t("story.recapture")}
  • {t("story.delete")}
); }; const Story = (props: Props) => { const story = props.story; const bodyText = getTruncatedContent(story.text); const theme = useTheme(); const { t } = useTranslation(); const storyRef = useRef(null); const closeHandler = () => { hideList(props); }; useEffect(() => { window.addEventListener("click", closeHandler); return () => window.removeEventListener("click", closeHandler); }); return ( <>
{props.index + 1} {story.title && story.title.length > 0 ? story.title : t("story.untitledScene")}
{props.recaptureStorySuccessful && ( )} {props.menuOpen && }
{bodyText.length > 0 && ( {bodyText} )}
); }; const MenuButton = styled(RawButton)` padding: 0 10px 0 10px; min-height: 40px; border-radius: ${(props) => props.theme.radiusSmall}; background: transparent; &:hover, &:focus { opacity: 0.9; background-color: ${(props) => props.theme.dark}; } `; export default sortable(Story);