import { TrashIcon, ArchiveIcon, EditIcon, PublishIcon, MoveIcon, CheckboxIcon, } from "outline-icons"; import * as React from "react"; import { useTranslation } from "react-i18next"; import { useLocation } from "react-router-dom"; import { CompositeStateReturn } from "reakit/Composite"; import styled, { css } from "styled-components"; import Document from "~/models/Document"; import Event from "~/models/Event"; import Avatar from "~/components/Avatar"; import CompositeItem, { Props as ItemProps, } from "~/components/List/CompositeItem"; import Item, { Actions } from "~/components/List/Item"; import Time from "~/components/Time"; import usePolicy from "~/hooks/usePolicy"; import RevisionMenu from "~/menus/RevisionMenu"; import { documentHistoryUrl } from "~/utils/routeHelpers"; type Props = { document: Document; event: Event; latest?: boolean; } & CompositeStateReturn; const EventListItem = ({ event, latest, document, ...rest }: Props) => { const { t } = useTranslation(); const location = useLocation(); const can = usePolicy(document.id); const opts = { userName: event.actor.name, }; const isRevision = event.name === "revisions.create"; let meta, icon, to; const ref = React.useRef(null); // the time component tends to steal focus when clicked // ...so forward the focus back to the parent item const handleTimeClick = React.useCallback(() => { ref.current?.focus(); }, [ref]); switch (event.name) { case "revisions.create": case "documents.latest_version": { if (latest) { icon = ; meta = t("Latest version"); to = documentHistoryUrl(document); break; } else { icon = ; meta = t("{{userName}} edited", opts); to = documentHistoryUrl(document, event.modelId || ""); break; } } case "documents.archive": icon = ; meta = t("{{userName}} archived", opts); break; case "documents.unarchive": meta = t("{{userName}} restored", opts); break; case "documents.delete": icon = ; meta = t("{{userName}} deleted", opts); break; case "documents.restore": meta = t("{{userName}} moved from trash", opts); break; case "documents.publish": icon = ; meta = t("{{userName}} published", opts); break; case "documents.move": icon = ; meta = t("{{userName}} moved", opts); break; default: console.warn("Unhandled event: ", event.name); } if (!meta) { return null; } const isActive = location.pathname === to; if (document.isDeleted) { to = undefined; } return ( } image={} subtitle={ {icon} {meta} } actions={ isRevision && isActive && event.modelId && can.update ? ( ) : undefined } ref={ref} {...rest} /> ); }; const BaseItem = React.forwardRef( ({ to, ...rest }: ItemProps, ref?: React.Ref) => { if (to) { return ; } return ; } ); const Subtitle = styled.span` svg { margin: -3px; margin-right: 2px; } `; const ItemStyle = css` border: 0; position: relative; margin: 8px; padding: 8px; border-radius: 8px; img { border-color: transparent; } &::before { content: ""; display: block; position: absolute; top: -4px; left: 23px; width: 2px; height: calc(100% + 8px); background: ${(props) => props.theme.textSecondary}; opacity: 0.25; } &:nth-child(2)::before { height: 50%; top: auto; bottom: -4px; } &:last-child::before { height: 50%; } &:first-child:last-child::before { display: none; } ${Actions} { opacity: 0.5; &:hover { opacity: 1; } } `; const ListItem = styled(Item)` ${ItemStyle} `; const CompositeListItem = styled(CompositeItem)` ${ItemStyle} `; export default EventListItem;