import type { ReactIsland } from "@ethicdevs/react-monolith";
import React from "react";
import styled, { css } from "styled-components";
import type { Organization, Repository } from "@prisma/client";
import type {
RepositoryForkedFromRepoMeta,
WithThemeSchemeProp,
} from "../types";
import { buildRouteLink } from "../utils/shared";
import { ButtonAnchor } from "../components/Button.styled";
import { BackIcon } from "../components/icons/BackIcon";
import { GitForkIcon } from "../components/icons/GitForkIcon";
import { Grid } from "../components/Grid";
import { AppRoute } from "../routes.defs";
import { Colors, NamedColors } from "../utils/style";
import { useMediaQuery } from "../utils/hooks/useMediaQuery";
export interface RepositoryHeroProps {
parentOrg: Organization;
repo: Repository;
forkedFromRepo?: RepositoryForkedFromRepoMeta | null;
forksCount?: number;
path?: string;
separator?: string;
showForkButton?: boolean;
showNewButton?: boolean;
newButtonUrl?: string;
newButtonText?: string | JSX.Element;
}
const RepositoryHero: ReactIsland<
RepositoryHeroProps & WithThemeSchemeProp
> = ({
themeScheme,
parentOrg,
repo,
forkedFromRepo = null,
forksCount = 0,
path = undefined,
showForkButton = true,
showNewButton = false,
newButtonUrl = undefined,
newButtonText = "New Repository",
}) => {
const isMobile = useMediaQuery("sm");
return (
<Grid.Col
fluid
gap={16}
style={{
borderBottom: `1px solid ${NamedColors.BORDER_DEFAULT[themeScheme]}`,
}}
>
<Grid.Row fluid nowrap alignItems={"flex-start"}>
<StyledActionIconButtonAnchor
themeScheme={themeScheme}
onClick={
typeof window !== "undefined"
? () => window.history.back()
: undefined
}
visible
>
<BackIcon color={NamedColors.TEXT_DEFAULT[themeScheme]} size={24} />
</StyledActionIconButtonAnchor>
<Grid.Col
nowrap
flex={"1 0 300px"}
style={{ minWidth: 300, marginBottom: 12, marginLeft: 12 }}
>
<h2 style={{ margin: 0, fontSize: isMobile ? 20 : 20 }}>
<a
style={{ whiteSpace: "nowrap" }}
href={buildRouteLink(AppRoute.ORGANIZATION_DETAILS, {
orgSlug: parentOrg.slug,
})}
>
{parentOrg.displayName || parentOrg.slug}
</a>
{" / "}
<a
style={{ whiteSpace: "nowrap" }}
href={buildRouteLink(AppRoute.REPOSITORY_DETAILS, {
orgSlug: parentOrg.slug,
repoSlug: repo.slug,
})}
>
{repo.displayName || repo.slug}
</a>
</h2>
<div style={{ flex: 1 }}>
<h3
style={{
whiteSpace: "nowrap",
margin: 0,
marginTop: 4,
fontSize: 16,
fontWeight: "700",
fontFamily: "monospace",
}}
>
{path || "Files"}
</h3>
</div>
<div style={{ flex: 1 }}>
{repo.isFork && forkedFromRepo != null && (
<h5 style={{ margin: 0, marginTop: 8 }}>
<span>Forked From</span>
{" ∙ "}
<a
href={buildRouteLink(AppRoute.ORGANIZATION_DETAILS, {
orgSlug: forkedFromRepo.organization.slug,
})}
>
{forkedFromRepo.organization.displayName ||
forkedFromRepo.organization.slug}
</a>
{" / "}
<a
href={buildRouteLink(AppRoute.REPOSITORY_DETAILS, {
orgSlug: forkedFromRepo.organization.slug,
repoSlug: forkedFromRepo.slug,
})}
>
{forkedFromRepo.displayName || forkedFromRepo.slug}
</a>
</h5>
)}
</div>
</Grid.Col>
{showForkButton && (
<ButtonAnchor
href={buildRouteLink(AppRoute.REPOSITORY_FORK, {
orgSlug: parentOrg.slug,
repoSlug: repo.slug,
})}
>
<Grid.Row
nowrap
justifyContent={"center"}
alignItems={"center"}
gap={8}
>
<GitForkIcon color={Colors.WHITE_01} size={24} />
<span>Fork</span>
<span
style={{
padding: "2px 6px",
minWidth: 20,
background: "rgba(0,0,0,0.1)",
borderRadius: 8,
fontSize: 12,
}}
>
{forksCount}
</span>
</Grid.Row>
</ButtonAnchor>
)}
{showNewButton && (
<ButtonAnchor href={newButtonUrl}>{newButtonText}</ButtonAnchor>
)}
</Grid.Row>
</Grid.Col>
);
};
RepositoryHero.displayName = "RepositoryHero";
export default RepositoryHero;
const StyledActionIconButtonAnchor = styled.button<
WithThemeSchemeProp & { visible?: boolean }
>`
${({ themeScheme, visible = true }) => css`
display: ${visible ? "flex" : "none"};
justify-content: center;
align-items: center;
width: 44px;
min-width: 44px;
max-width: 44px;
height: 44px;
min-height: 44px;
max-height: 44px;
padding-top: -2px;
font-size: 14px;
font-weight: thin;
color: ${NamedColors.TEXT_MUTED[themeScheme]};
background: ${NamedColors.CARD_OVERLAY[themeScheme]};
border-image: none;
border: none;
border-radius: 22px;
cursor: pointer;
&.active,
&:hover {
color: ${NamedColors.TEXT_DEFAULT[themeScheme]};
background: ${NamedColors.CARD[themeScheme]};
}
&:active {
font-size: 22px;
}
`}
`;