/*
* Copyright (c) 2020 - present Cloudogu GmbH
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://www.gnu.org/licenses/.
*/
import React, { FC, ReactNode, useState } from "react";
import { useNavigate, useLocation } from "react-router";
import { urls } from "@scm-manager/ui-api";
import styled from "styled-components";
import Icon from "../Icon";
import Tooltip from "../Tooltip";
import { useTranslation } from "react-i18next";
import copyToClipboard from "../CopyToClipboard";
/**
* Adds anchor links to markdown headings.
*
* @see Headings are missing anchors / ids
*/
const Link = styled.a`
i {
font-size: 1rem;
visibility: hidden;
margin-left: 10px;
}
i:hover {
cursor: pointer;
}
&:hover i {
visibility: visible;
}
`;
type Props = {
children: ReactNode;
level: number;
permalink: string;
id?: string;
};
function flatten(text: string, child: any): any {
return typeof child === "string" ? text + child : React.Children.toArray(child.props.children).reduce(flatten, text);
}
/**
* Turns heading text into a anchor id
*
* @VisibleForTesting
*/
export function headingToAnchorId(heading: string) {
return heading.toLowerCase().replace(/\W/g, "-");
}
const MarkdownHeadingRenderer: FC = ({ children, level, permalink, id }) => {
const [copying, setCopying] = useState(false);
const [t] = useTranslation("repos");
const location = useLocation();
const navigate = useNavigate();
const reactChildren = React.Children.toArray(children);
const heading = reactChildren.reduce(flatten, "");
const anchorId = id || headingToAnchorId(heading);
const copyPermalink = (event: React.MouseEvent) => {
event.preventDefault();
setCopying(true);
copyToClipboard(permalinkHref)
.then(() => navigate("#" + anchorId, { replace: true }))
.finally(() => setCopying(false));
};
const CopyButton = copying ? (
) : (
);
const headingElement = React.createElement("h" + level, { id: anchorId }, [...reactChildren, CopyButton]);
const href = urls.withContextPath(location.pathname + "#" + anchorId);
const permalinkHref =
window.location.protocol +
"//" +
window.location.host +
urls.withContextPath((permalink || location.pathname) + "#" + anchorId);
return (
{headingElement}
);
};
export const create = (permalink: string): FC => {
return (props) => ;
};
export default MarkdownHeadingRenderer;